Palaeogeographical Maps
Maps are essential when discussing occurrences of taxa, both in the present and the past. Chuck in the issues associated with continental drift, and it can be difficult to place the wider context of some fossil occurrences. ‘These marine fossils are found at the top of a mountain, but where were the oceans 150 million years ago?’ Here are a couple of recent examples discussing the spread of occurrences, in this case Jurassic marine reptiles.
Reconstructing global palaeogeography has been an ongoing task for many decades, and both local and global reconstructions and compendia have been made (e.g. Bradshaw et al. 1992). But the case of making maps to show many occurrences by hand can be difficult and time-consuming.
A few examples of groups that have made efforts to create palaeogeographical maps at various points through the Phanerozoic include Ron Blakey at Deep Time Maps (https://deeptimemaps.com) and Christopher Scotese leading the Paleomap Project (http://scotese.com).
DeepTimeMaps_Animation_Mollweide_Sample from 42 Degrees North Media on Vimeo.
While built from models of plate tectonics and continental drift, these are nonetheless individual time points in a continuous series and open to some interpretation.
GPlates
GPlates (https://www.gplates.org) is free software that reconstructs the movement of tectonic plates through geological history. Using models of plate movement, the configuration can be reconstructed at arbitrary points in the past. Onto this, the palaeoenvironments of the formations at their current positions can be overlain, and so the positions of landmasses, mountains, coastlines, and marine settings can be plotted long back in time.
The download from GPlates provides lots of example data and projects to show the various plates, tectonics, plumes and other information that can be included. New data are being added as research is published. Try, for instance, the DataBundleForNovices project (GplatesSampleData/DataBundleForNovices) to see a combined model of modern continents and ocean spreading over the last 410 million years.
There is also a GPlates Web Service (GWS; http://gws.gplates.org) that can provide some of the same data without the software. I’ll look briefly at this first.
Exercises 1
- Find an example of a palaeogeographical map for your favourite time period.
- Have a look in the folder
GplatesSampleData to see what other projects are included.
Automatic map plotting in R
A couple of packages already exist for using GPlates reconstructions to create palaeogeographical maps in R:
Both of these download from GWS. I’ve borrowed some of their functions for this lab group.
If you’re unfamiliar with RStudio or RMarkdown (.Rmd files), then the code sections are placed in ‘chunks’ like the one below. You can run individual lines by Cmd+Enter or Ctrl+Enter, or run the whole chunk using the little green arrow to the top right of each chunk. Try with this chunk below if you want.
library(broom)
library(dplyr)
Attaching package: 'dplyr'
The following objects are masked from 'package:stats':
filter, lag
The following objects are masked from 'package:base':
intersect, setdiff, setequal, union
library(forcats)
library(ggplot2)
Keep up to date with changes at https://www.tidyverse.org/blog/
library(ggthemes)
library(mapproj)
Loading required package: maps
library(purrr)
Attaching package: 'purrr'
The following object is masked from 'package:maps':
map
library(readr)
library(rgdal)
Loading required package: sp
rgdal: version: 1.5-23, (SVN revision 1121)
Geospatial Data Abstraction Library extensions to R successfully loaded
Loaded GDAL runtime: GDAL 3.1.4, released 2020/10/20
Path to GDAL shared files: /Library/Frameworks/R.framework/Versions/4.0/Resources/library/rgdal/gdal
GDAL binary built with GEOS: TRUE
Loaded PROJ runtime: Rel. 6.3.1, February 10th, 2020, [PJ_VERSION: 631]
Path to PROJ shared files: /Library/Frameworks/R.framework/Versions/4.0/Resources/library/rgdal/proj
Linking to sp version:1.4-5
To mute warnings of possible GDAL/OSR exportToProj4() degradation,
use options("rgdal_show_exportToProj4_warnings"="none") before loading rgdal.
library(stringr)
library(tibble)
# library(tidyverse) # a quick way to load packages, but slow for Binder.
list.files("functions/", pattern = "\\.R", full.names = TRUE) %>%
walk(source)
NB not all of the chunks below should be run on Binder as some of the code will take a long time or fail to execute.
GPlates Web Service
GWS can reconstruct the locations of points, coastlines, plates, paths, and features back into the past (https://github.com/GPlates/gplates_web_service_doc/wiki). It can also use a variety of different reconstructions. Most relevant is perhaps the Golonka (2007) model, which is often used for palaeocoordinate reconstruction in the Palaeobiology Database (PBDB).
The process is:
- Download outlines of the continental coastlines.
- Download outlines of the tectonic plates.
- Read and convert these into a format that R and ggplot2 can use,
- this uses the packages rgdal, readr, and broom.
- Plot,
- in this case with gpplot.
Example code only. Do not run. The code below does these steps by downloading the data, which will likely take some time.
#### DO NOT RUN THIS CODE ####
coastline_gws_url <-
"http://gws.gplates.org/reconstruct/coastlines/?time=155&model=GOLONKA"
polygons_gws_url <-
"http://gws.gplates.org/reconstruct/static_polygons/?time=155&model=GOLONKA"
kimmeridgian_coastlines <-
rgdal::readOGR(coastline_gws_url) %>%
broom::tidy()
kimmeridgian_polygons <-
rgdal::readOGR(polygons_gws_url) %>%
broom::tidy()
This chunk below replicates the above using data I’ve already downloaded from GWS and stored in the GitHub repository, and can be used on Binder. It has the same steps of loading and tidying the data, then includes the commands to plot with ggplot2.
Feel free to run this code.
# Load and tidy the data
kimmeridgian_coastlines <-
readOGR(
"data/GWS/Matthews_etal_GPG_2016_Coastlines_reconstructed_155.00Ma.gmt"
) %>%
tidy()
kimmeridgian_polygons <-
readOGR(
"data/GWS/Matthews_etal_GPG_2016_Polygons_reconstructed_155.00Ma.gmt"
) %>%
tidy()
ggplot() +
geom_map(
data = kimmeridgian_polygons,
map = kimmeridgian_polygons,
aes(x = long, y = lat, map_id = id),
fill = "#D8D8D8"
) +
geom_map(
data = kimmeridgian_coastlines,
map = kimmeridgian_coastlines,
aes(x = long, y = lat, map_id = id),
colour = "#222222", fill = NA, size = 0.3
) +
coord_map("mollweide") +
map_border() +
theme_map()
When plotting, the data are added as layers, each plotting over the other: plate polygons at the bottom then coastlines on top. I’ve also set the map projection to be Mollweide, but you can play with this and change it to others included in the mapproj package function mapproject. Options include "Gilbert", "fisheye", and "hex". (Use, for example, coord_map("fisheye", n = 0.7) to add extra arguments.)
Additionally I’ve added a border (map_border(), in the functions folder) and used a basic theme (theme_map()) to get a plain background.
How R plots these map data
The positions and extent of map areas from data in GPlates are stored as a series of polygons. Each region is outlined by a series of points that form a closed shape, filled with a particular colour. This is exported from GPlates as OGR-GMT format, with file extension .gmt, which lists each point that marks the corner of a polygon. In R, broom converts this to a tibble (similar to a data.frame) that has the x and y locations of each point, and a series of columns that identify which polygon that point belongs to. These ID columns are important to make sure that polygons contain the correct points and are closed properly. Without these, there would only be a single shape that would stretch across the whole globe and not make much sense.
Not quite right
GWS is convenient for data and access, but the results in the plot above show the current continental coastlines and the plates. This does not reflect the ancient coastlines that were really after. Also, many of the countries are cross-cut by the polygons that form the sections in the model, which are untidy and typically not visible.
We need to go to the next level: true palaeogeographical reconstructions. Fortunately GPlates offers that too.
Exercises 2
- Have a look at the GWS documentation. What address would you use to get reconstructed coastlines in the early Carboniferous using the Matthews et al. (2016) model?
- Open an example of the OGR-GMT data from the GWS, either from the
data/GWS folder or by downloading it. Can you see how the polygons are stored? How are different polygons identified?
- Now look at the tidied version in R, i.e.
kimmeridgian_coastlines or kimmeridgian_polygons. By default this will only show the first 10 rows, but you can see more with, for example, head(kimmeridgian_polygons, n = 50L). Can you see how the OGR-GMT data is transferred to this tidy format?
- Play around with the inputs to the plot above. How messy or colourful can you make this map? What options are there in
theme_map()? (Hint: use ?theme_map to see.)
‘True’ Palaeogeographical Outlines
Among the projects included with the GPlates download is the set of palaeogeographical reconstructions by Cao et al. (2017) for the last 402 my. These are based, and so should align nicely, with the Golonka (2007) model that is used for data in the PBDB, which we’ll get to below. These data are in GPlatesSampleData/FeatureCollections/Palaeogeography/Global/.
Cao et al. (2017) used a combination of previous palaeogeographical reconstructions, and updated the coastlines, mountains, and extent of land and ice caps using occurrence data from the PBDB. In a few locations, what had been reconstructed as land produced marine fossils, when accounting for the movement of plates, and vice versa.
These reconstructions include four layers that have the separated palaeoevonvironmental regions:
- Shallow marine: shelf seas.
- Land: terrestrial habitats outlined by coastlines.
- Mountain: areas of mountain building and uplift.
- Ice cap: polar regions that have substantial evidence for long term presence of ice.
These are given the abbreviations ‘sm,’ ‘l,’ ‘m’ and ‘i.’ It’s worth noting that the way these are built means that the layers have to be plotted in the order above – shallow marine first, ice cap last. There are various areas that overlap (Australia especially) so the order of overlay becomes important in making the correct boundaries visible.
Export from GPlates
The Cao et al. (2017) reconstructions aren’t available from GWS, but can be exported from GPlates directly using the menu item Reconstruction > Export… Like above I’ve already done this for an example data set, in this case using the Late Jurassic (Kimmeridgian, 155 Ma) as an example. To make your own, once in the export window:
- Select the time of export (can be set from the main window time).
- Also an option to export a series at regular intervals.
- The layers to export
- select Add Export… under Export Data
- choose Reconstructed Geometries
- output as OGR-GMT
- choose single or multiple files
- I prefer multiple: you get one file for each of sea/land/mountain/ice. This is the form that works with the code below.
- OK
- Change Target directory: to somewhere you can find.
- Begin Export
The example data are in data/palaeogeography as three .gmt files that describe the polygon outlines for each of the layers. Note that as there are no ice caps at this time, there are only three files/layers. Look at the Carboniferous of later Palaeogene to get some ice caps.
Read in the map data
I find it useful to tie together the layers and colours from the beginning of importing – this ensures keeping the layers in the order for plotting. The data files are:
lm_402_2_reconstructed_155.00Ma.gmt: landmass
m_402_2_reconstructed_155.00Ma.gmt: mountain
sm_402_2_reconstructed_155.00Ma.gmt: shallow marine
This short code snippet sets lists the layer names and assigns the colours for each layer on the map – they are similar to those shown in GPlates, but not quite the same. I’ve also used #DAD3FF for ice caps when needed. (Technically this isn’t used for the colours, that’s in the palaeogeog_map_niceties function, this is somewhat a remnant of a previous way that I made this.)
map_layers <-
c(
"Land" = "#FFD23A",
"Mountain" = "#FF8D51",
"Shallow marine" = "#45D8FF"
)
With that ready, the following code reads and tidies the data (as for above), then adds a column (geog_layer) to identify the data layer (shallow marine, land, mountain) and joins all the data together. It’s very tidyverse based, so I’d suggest looking at https://www.tidyverse.org to see the rationale and how they link using the pipe (%>%). You can also see more about individual functions in the R help.
The final step is to create a column (polygon_id) to identify each region on the, which come after mountain map. I had a long issue where different continents would join up, or Australia’s land would always appear plotted underneath the sea. As described above, this is because the shapes on the map are plotted as separate polygons, and the IDs are repeated between each of the layers. We’ll use the polygon_id column to make sure that each polygon has a unique ID by joining the layer, group and id name from the tidied data.
polygon_data <-
list.files("data/palaeogeography/", pattern = ".gmt", full.names = TRUE) %>%
map(readOGR) %>%
map(tidy) %>%
map2(
names(map_layers),
~ add_column(.x, geog_layer = .y)
) %>%
bind_rows() %>%
mutate(
polygon_id = str_c(id, group, geog_layer) %>% as_factor(),
geog_layer = factor(geog_layer, labels = names(map_layers))
)
OGR data source with driver: OGR_GMT
Source: "/Users/bcm/GitHub/palaeomap_example/data/palaeogeography/lm_402_2_reconstructed_155.00Ma.gmt", layer: "lm_402_2_reconstructed_155.00Ma"
with 361 features
It has 20 fields
OGR data source with driver: OGR_GMT
Source: "/Users/bcm/GitHub/palaeomap_example/data/palaeogeography/m_402_2_reconstructed_155.00Ma.gmt", layer: "m_402_2_reconstructed_155.00Ma"
with 195 features
It has 20 fields
OGR data source with driver: OGR_GMT
Source: "/Users/bcm/GitHub/palaeomap_example/data/palaeogeography/sm_402_2_reconstructed_155.00Ma.gmt", layer: "sm_402_2_reconstructed_155.00Ma"
with 808 features
It has 20 fields
Regions defined for each Polygons
Regions defined for each Polygons
Regions defined for each Polygons
Arranging the map layers
At this point it’s important to have the map layers in the correct order, so that marine is plotted under land, which is plotted under mountain.
This piece of code does that for you, ensuring shallow marine is first (it was third in map_layers above) then assigning this order to the polygon_id column. It converts the polygon_id column to a factor and re-orders thee levels based on the reordered map_layers.
id_level_order <-
map_layers[c(3, 1, 2)] %>%
map(
function(layr) polygon_data$polygon_id %>% levels() %>% str_which(layr)
) %>%
unlist()
polygon_data <-
polygon_data %>%
mutate(
polygon_id = fct_relevel(polygon_id, levels(polygon_id)[id_level_order])
)
Plotting the map
Unfortunately, using the same plot layer method as for the GWS data above is a little excessive. You would have to add a new annotation for each layer (just about okay for three, tedious for more), which then multiplies when plotting reconstructions of many times.
# DO NOT RUN THIS CODE
ggplot() +
geom_map() +
geom_map() +
geom_map() + …
Instead, you can use the function geom_polygon and have the different layers plotted automatically with the colours assigned above. The fill is the most important argument as that assigns the main bulk of the colour. The colour argument is the outline, which you shouldn’t use bas that will outline the map layers and change their shape. The colour argument will be used when plotting occurrence points (see below). Also having the ordered and correctly grouped polygon_id is important here as that determines how the individual polygons are grouped and closed, preventing shapes from spanning the globe, or incorrectly overlapping.
I’ll point out here that there’s quite a lot going on in the palaeogeog_map_niceties function at the end. This is a collection of theme options and a colour scale to show the map properly. In particular this adds the outline and the lines of the equator and tropics. I guess one thing to note is that the ‘tropics,’ in a biodiversity sense, may not be the same in the past as the present. Increased temperatures can change the latitudinal biodiversity gradient. Also, obliquity and precession change the latitudes of the astronomical tropics through time.
# dev.new(width = 7, height = 4)
map_plot <-
ggplot() +
geom_polygon(
data = polygon_data,
aes(
x = long,
y = lat,
fill = geog_layer,
group = polygon_id
),
colour = NA
) +
coord_map("mollweide") +
theme_map() +
palaeogeog_map_niceties()
map_plot
You can try changing the look by modifying the projection (coord_map) and play about with some of the colours and markings by editing the function palaeogeog_map_niceties (functions/palaeogeog_map_niceties.R). You can also add further annotations (https://ggplot2-book.org/annotations.html#annotations) or change labels as you wish.
Going further 1: locating with modern coastlines
You may also want to add outlines of modern coastlines to show where these are and help locating. Again these are not available from GWS, but can be exported from GPlates. In GPlates, from File > Open Feature Collection… go to GplatesSampleData/FeatureCollections/Coastlines and load Matthews_etal_GPC_2016_Coastlines_Polyline.gpmlz. This adds a new layer into GPlates with areas of modern coastline in their relative positions for the time. Not all the modern coastlines are there as not all of these have certain locations, or rock to be found at – these come and go at different time points.
Like above, you can export this layer from GPlates. In this repo, I’ve already done that to data/coastlines/, which you can load with this code.
modern_coastlines <-
readOGR("data/coastlines/Matthews_etal_GPC_2016_Coastlines_Polyline_reconstructed_155.00Ma.gmt") %>%
tidy() %>%
add_column(geog_layer = "Modern coastlines") %>%
mutate(polygon_id = str_c(id, group, geog_layer) %>% as_factor())
This layer needs the same organising of IDs as the palaeogeography above, but once done can be easily added to map_plot above. This is where it’s useful to save your ggplot to an object alongside printing it – this you can just add new layers on top of the base map.
map_plot +
geom_path(
data = modern_coastlines,
aes(
x = long,
y = lat,
group = polygon_id,
),
colour = "#888888", size = 0.3
)
Exercises 3
- Try plotting this map with different projections (see above and
?mapproject). Does this work well for all projections? Why?
- Look at the code behind
palaeogeog_map_niceties() (in functions/palaeogeog_map_niceties.R). Modify this to add different lines of latitude. Can you add lines of longitude too? What about changing the colour?
- ggplot objects can have new layers added to them one-by-one by using
+, but you can also combine them into function containing a list of layers that can be added in a single line.
- Hint: to change the colour of the map layers, use
fill.
- Can you try creating your own palaeogeographical map for your favourite time? This should be done on your own computer. Follow the instructions above to export data from GPlates then plot in R, making sure you change all the file and object names.
Adding Fossil Occurrences
Getting occurrence data
Now that you’ve spent lots of time making a pretty map, let’s plot some fossils on top of it.
Of course, being me and having used Jurassic data, we’re going to plot some ichthyosaurs. In this instance, the occurrence data comes from the PBDB, downloading ichthyosaur occurrences with these filters:
- Callovian–Tithonian (166-145 Ma)
- all levels of taxonomy – no filtering.
The PBDB has its own web API (https://paleobiodb.org/data1.2) from which you can get occurrences, collections, taxonomy and other things. In the code chunk below I’ve crafted the URL to download the data, but this is already in the repo so doesn’t need to be run.
Do not run the following chunk, the data is already in the repo.
#### DO NOT RUN THIS CHUNK ####
pbdb_url <-
"https://paleobiodb.org/data1.2/occs/list.csv?base_name=Ichthyosauromorpha&interval=Callovian,Oxfordian,Kimmeridgian,Tithonian&show=paleoloc"
occ_ichthyosaurs <-
read_csv(pbdb_url)
The part of the URL show=paleoloc is the important bit as the PBDB has already computed the palaeocoordinates of most occurrences using their modern location and the ages of the occurrences. Conveniently using the same default GPlates model as the palaeogeography.
Plotting occurrences
With that all done, use the chunk below to add the occurrences onto the base map. These are plotted with geom_point(), which you may be familiar with, setting the x and y values to the palaeolongitude and palaeolatitude respectively.
occ_ichthyosaurs <-
read_csv("data/occurrences/2021-02-18-ichthyosaur-occurrences.csv")
── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
cols(
.default = col_character(),
occurrence_no = col_double(),
reid_no = col_double(),
flags = col_logical(),
collection_no = col_double(),
identified_no = col_double(),
accepted_no = col_double(),
max_ma = col_double(),
min_ma = col_double(),
reference_no = col_double(),
paleolng = col_double(),
paleolat = col_double()
)
ℹ Use `spec()` for the full column specifications.
occ_plot <-
map_plot +
geom_point(
data = occ_ichthyosaurs,
aes(
x = paleolng,
y = paleolat
)
)
occ_plot
The more eagle-eyed of you may notice that some of these marine ichthyosaur occurrences are located resolutely in the middle of landmasses. There are a few possible reasons for that:
- The palaeogeographical reconstruction is wrong.
- The modern location for the occurrence is wrong, so the palaeocoordinates are wrong.
- The age of the occurrence is wrong, so its reconstructed position is wrong.
These three are worth considering further.
Incorrect palaeogeographical reconstruction is perhaps the most obvious answer: these reconstructions are difficult and there will always be some uncertainty with reconstructing the earth 155 million years ago. However, the method of Cao et al. (2017) included palaeoenvironments reconstructed using PBDB data to improve confidence in the borders of sea and land. The palaeogeography should match the PBDB well then, particularly in well-studied and sampled periods and locations. There are, however, some parts that cannot certainly reconstructed because of a lack of data, rock availability, or accessibility.
Incorrect modern location may be the easiest to discount as localities tend to be spatially constrained and identifiable, even in older literature. This being the case, there should only be minor error in the locations of occurrences (~10s km).
Incorrect age assignment is probably the most likely cause, or perhaps better imprecise ages. The palaeocoordinates calculated for each occurrence in the PBDB use the midpoint of its temporal range. Sometimes this range can be quite large, such as the several species of Undorosaurus that cover the whole Late Jurassic (163.5–145 Ma in GTS 2020/03). Those specimens from Patagonia that are plotted in the middle of the land are also similarly imprecisely dated. Their palaeocoordinates are reconstructed to the middle Kimmeridgian, whereas they are likely later (given the occurrence of ichthyosaurs from similar locations) when there was a sea there to swim in.
As the ichthyosaur occurrences included over over 20 my of earth history there will be changes in palaeogeography, and some potentially imprecise dating.
The ways around this are to have more time slices with the occurrences plotted, but this complicates the code and any plots, and such precise reconstructions may not be available. Alternatively, aim to use only the most precisely dated occurrences, if possible, but this can remove lots of useful data. Ultimately, you may just have to accept that some marine occurrences may appear on land, or vice versa.
Going further 2: separating occurrences with facets
The final thing that you can try is the faceting power of ggplot2 to separate the different groups of occurrences. Below, this code splits out the occurrences by their accepted taxonomic rank. Most occurrences are just non-diagnostic vertebral material, so can’t be assigned to a family, genus or species. These are listed under ‘unranked_clade.’
Conveniently, creating facets is as simple as adding a single line.
occ_plot +
facet_wrap(vars(accepted_rank), ncol = 1)
Exercises 4
- Look at the PBDB web API (https://paleobiodb.org/data1.2). What other options and data sets can you access with this? Can you craft a URL that will download occurrence data of Tithonian bivalves.
- This download may not work on Binder, so you should do it in R on your own computer.
- Try adding colour or shapes to you occurrence points using the options in
geom_point.
- Download and plot the palaeogeographical map and occurrences for your favourite group in your favourite stage. Again this should be done on your own computer. Beware it may take a while if you want to plot many occurrences.
- It’s also useful to separate out occurrences on the map, for instance, can you colour occurrences within the outside the tropics differently? say red in the tropics (±23.5°) and blue outside.
- Hint: you can use the palaeocoordinates of the PBDB data to assign a group to each occurrence, use this to colour the points in
geom_point.
- Hint: use
scale_colour_discrete to colour the points. See the code of palaeogeog_map_niceties (functions/palaeogeog_map_niceties.R) for an example of doing this.
LS0tCnRpdGxlOiAiUGxvdHRpbmcgUGFsYWVvZ2VvZ3JhcGhpY2FsIE1hcHMgaW4gUjogYSBMYWIgR3JvdXAiCmF1dGhvcjogI0JlbiBNb29uCiAgLSBuYW1lOiBCZW4gTW9vbgogICAgYWZmaWxpYXRpb246IFBhbGFlb2Jpb2xvZ3kgUmVzZWFyY2ggR3JvdXAsIFNjaG9vbCBvZiBFYXJ0aCBTY2llbmNlcywgVW5pdmVyc2l0eSBvZiBCcmlzdG9sLCBCcmlzdG9sLCBVLksuCiAgICBlbWFpbDogYmVuamFtaW4ubW9vbkBicmlzdG9sLmFjLnVrCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCICVZJylgIgpmaWdfY2FwdGlvbjogdHJ1ZQpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGRmX3ByaW50OiBwYWdlZAogICAgY29kZV9mb2xkaW5nOiBzaG93IAogICAgIyBzZWxmX2NvbnRhaW5lZDogZmFsc2UKICAgICMga2VlcF9tZDogdHJ1ZQogICMgcGRmX2RvY3VtZW50OgogICMgICBrZWVwX3RleDogdHJ1ZQpiaWJsaW9ncmFwaHk6IGJpYmxpb2dyYXBoeS55YW1sCi0tLQoKIyBJbnRyb2R1Y3Rpb24gIwoKVGhpcyBndWlkZSB0YWtlcyB5b3UgdGhyb3VnaCB0d28gZGlmZmVyZW50IHdvcmsgZmxvd3MgdG8gY3JlYXRlIHBhbGFlb2dlb2dyYXBoaWNhbCBtYXBzIGFuZCBwbG90IG9jY3VycmVuY2VzIGZvc3NpbCB0YXhhIGluIFIuIEFsbCB0aGUgY29kZSBhbmQgZGF0YSBhcmUgaW4gdGhpcyBHaXRIdWIgcmVwb3NpdG9yeTogPGh0dHBzOi8vZ2l0aHViLmNvbS9iZW5qYW1pbm1vb24vcGFsYWVvbWFwX2V4YW1wbGU+CgpZb3UgY2FuIGRvd25sb2FkIGFuZCBydW4gdGhpcyBjb2RlIGRpcmVjdGx5IG9uIHlvdXIgbWFjaGluZSwgb3IgZm9sbG93IGFsb25nIG9ubGluZSBhdCBCaW5kZXIgd2hlcmUgSSd2ZSBjcmVhdGVkIGFuIGVudmlyb25tZW50IHdpdGggYWxsIG9mIHRoZSBkYXRhIHlvdSBuZWVkLiBDbGljayB0aGUgbGluayBiZWxvdyB0byBvcGVuIHRoaXMgaW4geW91ciB3ZWIgYnJvd3Nlci4KClshW0JpbmRlcl0oaHR0cHM6Ly9teWJpbmRlci5vcmcvYmFkZ2VfbG9nby5zdmcpXShodHRwczovL215YmluZGVyLm9yZy92Mi9naC9iZW5qYW1pbm1vb24vcGFsYWVvbWFwX2V4YW1wbGUvSEVBRD91cmxwYXRoPXJzdHVkaW8pCgpUaGUgQmluZGVyIGxpbmsgd2lsbCBvcGVuIGluIHlvdXIgYnJvd3NlciBpbiB0aGUgUlN0dWRpbyBpbnRlcmZhY2UuIE9wZW4gdGhlIGZpbGUgYHBhbGFlb21hcF9sYWJncm91cC5SbWRgIGZyb20gdGhlIGZpbGUgYnJvd3NlciB0byBnZXQgc3RhcnRlZC4KCiFbVGhlIFJTdHVkaW8gaW50ZXJmYWNlIHNpbWlsYXIgdG8gdGhhdCB5b3Ugc2hvdWxkIHNlZSBpbiBCaW5kZXIuIE9wZW4gdGhlIGZpbGUgYHBhbGFlb21hcF9sYWJncm91cC5uYi5odG1sYCB0byBnZXQgc3RhcnRlZC5dKC4vZmlncy9yc3R1ZGlvX3dpbmRvdy5wbmcpCgoKIyBQYWxhZW9nZW9ncmFwaGljYWwgTWFwcyAjCgpNYXBzIGFyZSBlc3NlbnRpYWwgd2hlbiBkaXNjdXNzaW5nIG9jY3VycmVuY2VzIG9mIHRheGEsIGJvdGggaW4gdGhlIHByZXNlbnQgYW5kIHRoZSBwYXN0LiBDaHVjayBpbiB0aGUgaXNzdWVzIGFzc29jaWF0ZWQgd2l0aCBjb250aW5lbnRhbCBkcmlmdCwgYW5kIGl0IGNhbiBiZSBkaWZmaWN1bHQgdG8gcGxhY2UgdGhlIHdpZGVyIGNvbnRleHQgb2Ygc29tZSBmb3NzaWwgb2NjdXJyZW5jZXMuICdUaGVzZSBtYXJpbmUgZm9zc2lscyBhcmUgZm91bmQgYXQgdGhlIHRvcCBvZiBhIG1vdW50YWluLCBidXQgd2hlcmUgd2VyZSB0aGUgb2NlYW5zIDE1MCBtaWxsaW9uIHllYXJzIGFnbz8nIEhlcmUgYXJlIGEgY291cGxlIG9mIHJlY2VudCBleGFtcGxlcyBkaXNjdXNzaW5nIHRoZSBzcHJlYWQgb2Ygb2NjdXJyZW5jZXMsIGluIHRoaXMgY2FzZSBKdXJhc3NpYyBtYXJpbmUgcmVwdGlsZXMuCgohW0FzIGEgZmlyc3QgZXhhbXBsZSwgQEdhbzIwMTlKUCBkaXNjdXNzIHRoZSBvY2N1cnJlbmNlcyBvZiBKdXJhc3NpYyBwbGVzaW9zYXVycyBpbiBDaGluYS5dKGh0dHBzOi8vbWVkaWEuc3ByaW5nZXJuYXR1cmUuY29tL2Z1bGwvc3ByaW5nZXItc3RhdGljL2ltYWdlL2FydCUzQTEwLjExODYlMkZzNDI1MDEtMDE5LTAwNDMtNS9NZWRpYU9iamVjdHMvNDI1MDFfMjAxOV80M19GaWc0X0hUTUwucG5nKQoKIVtIZXJlLCBAWnZlcmtvdjIwMjBHTSBzaG93IG9jY3VycmVuY2VzIG9mIGljaHRoeW9zYXVycyBpbiB0aGUgRWFybHkgSnVyYXNzaWMuXShodHRwczovL3N0YXRpYy5jYW1icmlkZ2Uub3JnL2JpbmFyeS92ZXJzaW9uL2lkL3VybjpjYW1icmlkZ2Uub3JnOmlkOmJpbmFyeToyMDIwMTIyMzA5MTQ1Njk4NC0wMjUyOlMwMDE2NzU2ODIwMDAxMzUxOlMwMDE2NzU2ODIwMDAxMzUxX2ZpZzEucG5nKQoKUmVjb25zdHJ1Y3RpbmcgZ2xvYmFsIHBhbGFlb2dlb2dyYXBoeSBoYXMgYmVlbiBhbiBvbmdvaW5nIHRhc2sgZm9yIG1hbnkgZGVjYWRlcywgYW5kIGJvdGggbG9jYWwgYW5kIGdsb2JhbCByZWNvbnN0cnVjdGlvbnMgYW5kIGNvbXBlbmRpYSBoYXZlIGJlZW4gbWFkZSBbZS5nLiBAQnJhZHNoYXcxOTkyR1NMTV0uIEJ1dCB0aGUgY2FzZSBvZiBtYWtpbmcgbWFwcyB0byBzaG93IG1hbnkgb2NjdXJyZW5jZXMgYnkgaGFuZCBjYW4gYmUgZGlmZmljdWx0IGFuZCB0aW1lLWNvbnN1bWluZy4KCkEgZmV3IGV4YW1wbGVzIG9mIGdyb3VwcyB0aGF0IGhhdmUgbWFkZSBlZmZvcnRzIHRvIGNyZWF0ZSBwYWxhZW9nZW9ncmFwaGljYWwgbWFwcyBhdCB2YXJpb3VzIHBvaW50cyB0aHJvdWdoIHRoZSBQaGFuZXJvem9pYyBpbmNsdWRlIFJvbiBCbGFrZXkgYXQgX0RlZXAgVGltZSBNYXBzXyAoPGh0dHBzOi8vZGVlcHRpbWVtYXBzLmNvbT4pIGFuZCBDaHJpc3RvcGhlciBTY290ZXNlIGxlYWRpbmcgdGhlIF9QYWxlb21hcCBQcm9qZWN0XyAoPGh0dHA6Ly9zY290ZXNlLmNvbT4pLgoKPGlmcmFtZSBzcmM9Imh0dHBzOi8vcGxheWVyLnZpbWVvLmNvbS92aWRlby8zMTU5MDcxMDY/dGl0bGU9MCZieWxpbmU9MCZwb3J0cmFpdD0wIiB3aWR0aD0iNjQwIiBoZWlnaHQ9IjMyMCIgZnJhbWVib3JkZXI9IjAiIGFsbG93PSJhdXRvcGxheTsgZnVsbHNjcmVlbjsgcGljdHVyZS1pbi1waWN0dXJlIiBhbGxvd2Z1bGxzY3JlZW4+PC9pZnJhbWU+CjxwPjxhIGhyZWY9Imh0dHBzOi8vdmltZW8uY29tLzMxNTkwNzEwNiI+RGVlcFRpbWVNYXBzX0FuaW1hdGlvbl9Nb2xsd2VpZGVfU2FtcGxlPC9hPiBmcm9tIDxhIGhyZWY9Imh0dHBzOi8vdmltZW8uY29tLzQyZGVncmVlc25vcnRoIj40MiBEZWdyZWVzIE5vcnRoIE1lZGlhPC9hPiBvbiA8YSBocmVmPSJodHRwczovL3ZpbWVvLmNvbSI+VmltZW88L2E+LjwvcD4KCjwhLS0gIVtQYWxhZW9nZW9ncmFwaHkgaW4gdGhlIExhdGUgSnVyYXNzaWMsIGFzIHJlY29uc3RydWN0ZWQgYXQgX0RlZXAgVGltZQpNYXBzLl9dKGh0dHBzOi8vZGVlcHRpbWVtYXBzLmNvbS93cC1jb250ZW50L3VwbG9hZHMvMjAxOC8wNy8xNTAtTWEtTW9sbC1fSnVyLUdQVC1taW4tMS03Njh4MzgyLmpwZykKLS0+CgohW1BhbGFlb2dlb2dyYXBoeSBvZiB0aGUgTGF0ZSBKdXJhc3NpYywgYXMgcmVjb25zdHJ1Y3RlZCBhdCBfUGFsYWVvbWFwIFByb2plY3QuX10oaHR0cDovL3d3dy5zY290ZXNlLmNvbS9pbWFnZXMvMTUyLmpwZykKCldoaWxlIGJ1aWx0IGZyb20gbW9kZWxzIG9mIHBsYXRlIHRlY3RvbmljcyBhbmQgY29udGluZW50YWwgZHJpZnQsIHRoZXNlIGFyZSBub25ldGhlbGVzcyBpbmRpdmlkdWFsIHRpbWUgcG9pbnRzIGluIGEgY29udGludW91cyBzZXJpZXMgYW5kIG9wZW4gdG8gc29tZSBpbnRlcnByZXRhdGlvbi4KCiMjIEdQbGF0ZXMgIyMKCkdQbGF0ZXMgKDxodHRwczovL3d3dy5ncGxhdGVzLm9yZz4pIGlzIGZyZWUgc29mdHdhcmUgdGhhdCByZWNvbnN0cnVjdHMgdGhlIG1vdmVtZW50IG9mIHRlY3RvbmljIHBsYXRlcyB0aHJvdWdoIGdlb2xvZ2ljYWwgaGlzdG9yeS4gVXNpbmcgbW9kZWxzIG9mIHBsYXRlIG1vdmVtZW50LCB0aGUgY29uZmlndXJhdGlvbiBjYW4gYmUgcmVjb25zdHJ1Y3RlZCBhdCBhcmJpdHJhcnkgcG9pbnRzIGluIHRoZSBwYXN0LiBPbnRvIHRoaXMsIHRoZSBwYWxhZW9lbnZpcm9ubWVudHMgb2YgdGhlIGZvcm1hdGlvbnMgYXQgdGhlaXIgY3VycmVudCBwb3NpdGlvbnMgY2FuIGJlIG92ZXJsYWluLCBhbmQgc28gdGhlIHBvc2l0aW9ucyBvZiBsYW5kbWFzc2VzLCBtb3VudGFpbnMsIGNvYXN0bGluZXMsIGFuZCBtYXJpbmUgc2V0dGluZ3MgY2FuIGJlIHBsb3R0ZWQgbG9uZyBiYWNrIGluIHRpbWUuCgpUaGUgZG93bmxvYWQgZnJvbSBHUGxhdGVzIHByb3ZpZGVzIGxvdHMgb2YgZXhhbXBsZSBkYXRhIGFuZCBwcm9qZWN0cyB0byBzaG93IHRoZSB2YXJpb3VzIHBsYXRlcywgdGVjdG9uaWNzLCBwbHVtZXMgYW5kIG90aGVyIGluZm9ybWF0aW9uIHRoYXQgY2FuIGJlIGluY2x1ZGVkLiBOZXcgZGF0YSBhcmUgYmVpbmcgYWRkZWQgYXMgcmVzZWFyY2ggaXMgcHVibGlzaGVkLiBUcnksIGZvciBpbnN0YW5jZSwgdGhlIF9EYXRhQnVuZGxlRm9yTm92aWNlc18gcHJvamVjdCAoYEdwbGF0ZXNTYW1wbGVEYXRhL0RhdGFCdW5kbGVGb3JOb3ZpY2VzYCkgdG8gc2VlIGEgY29tYmluZWQgbW9kZWwgb2YgbW9kZXJuIGNvbnRpbmVudHMgYW5kIG9jZWFuIHNwcmVhZGluZyBvdmVyIHRoZSBsYXN0IDQxMCBtaWxsaW9uIHllYXJzLgoKIVtUaGUgbWFpbiBHUGxhdGVzIHdpbmRvdyBzaG93aW5nIHRoZSBEYXRhQnVuZGxlRm9yTm92aWNlcyBsb2FkZWQuXSguL2ZpZ3MvZ3BsYXRlc193aW5kb3cucG5nKQoKIVtMYXllcnMgY2FuIGJlIHNlbGVjdGVkIGluIHRoaXMgR3BsYXRlcyB3aW5kb3cgdG8gc2hvdyBhbmQgaGlkZSBkaWZmZXJlbnQgZmVhdHVyZXMuXSguL2ZpZ3MvZ3BsYXRlc19sYXllcnMucG5nKQoKVGhlcmUgaXMgYWxzbyBhIEdQbGF0ZXMgV2ViIFNlcnZpY2UgKEdXUzsgPGh0dHA6Ly9nd3MuZ3BsYXRlcy5vcmc+KSB0aGF0IGNhbiBwcm92aWRlIHNvbWUgb2YgdGhlIHNhbWUgZGF0YSB3aXRob3V0IHRoZSBzb2Z0d2FyZS4gSSdsbCBsb29rIGJyaWVmbHkgYXQgdGhpcyBmaXJzdC4KCiMjIEV4ZXJjaXNlcyAxICMjCgoxLiBGaW5kIGFuIGV4YW1wbGUgb2YgYSBwYWxhZW9nZW9ncmFwaGljYWwgbWFwIGZvciB5b3VyIGZhdm91cml0ZSB0aW1lIHBlcmlvZC4KMi4gSGF2ZSBhIGxvb2sgaW4gdGhlIGZvbGRlciBgR3BsYXRlc1NhbXBsZURhdGFgIHRvIHNlZSB3aGF0IG90aGVyIHByb2plY3RzIGFyZSBpbmNsdWRlZC4gCgoKIyBBdXRvbWF0aWMgbWFwIHBsb3R0aW5nIGluIFIgIwoKQSBjb3VwbGUgb2YgcGFja2FnZXMgYWxyZWFkeSBleGlzdCBmb3IgdXNpbmcgR1BsYXRlcyByZWNvbnN0cnVjdGlvbnMgdG8gY3JlYXRlIHBhbGFlb2dlb2dyYXBoaWNhbCBtYXBzIGluIFI6CgoqIE5vbmFSL3BhbGVvTWFwICg8aHR0cHM6Ly9naXRodWIuY29tL05vbmFSL3BhbGVvTWFwPikKICAtIE5CIEhhcyBub3QgYmVlbiB1cGRhdGVkIGluIHNldmVyYWwgeWVhcnMuCiogTHVuYVNhcmUvZ3BsYXRlc3IgKDxodHRwczovL2dpdGh1Yi5jb20vTHVuYVNhcmUvZ3BsYXRlc3I+KQogIC0gTW9yZSByZWNlbnRseSB1cGRhdGVkLCBhbmQgc2ltaWxhciB0byBhYm92ZS4KCkJvdGggb2YgdGhlc2UgZG93bmxvYWQgZnJvbSBHV1MuIEkndmUgYm9ycm93ZWQgc29tZSBvZiB0aGVpciBmdW5jdGlvbnMgZm9yIHRoaXMgbGFiIGdyb3VwLgoKSWYgeW91J3JlIHVuZmFtaWxpYXIgd2l0aCBSU3R1ZGlvIG9yIFJNYXJrZG93biAoYC5SbWRgIGZpbGVzKSwgdGhlbiB0aGUgY29kZSBzZWN0aW9ucyBhcmUgcGxhY2VkIGluICdjaHVua3MnIGxpa2UgdGhlIG9uZSBiZWxvdy4gWW91IGNhbiBydW4gaW5kaXZpZHVhbCBsaW5lcyBieSBDbWQrRW50ZXIgb3IgQ3RybCtFbnRlciwgb3IgcnVuIHRoZSB3aG9sZSBjaHVuayB1c2luZyB0aGUgbGl0dGxlIGdyZWVuIGFycm93IHRvIHRoZSB0b3AgcmlnaHQgb2YgZWFjaCBjaHVuay4gVHJ5IHdpdGggdGhpcyBjaHVuayBiZWxvdyBpZiB5b3Ugd2FudC4KCmBgYHtyIHNldHVwfQpsaWJyYXJ5KGJyb29tKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGZvcmNhdHMpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3RoZW1lcykKbGlicmFyeShtYXBwcm9qKQpsaWJyYXJ5KHB1cnJyKQpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KHJnZGFsKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkodGliYmxlKQojIGxpYnJhcnkodGlkeXZlcnNlKSAjIGEgcXVpY2sgd2F5IHRvIGxvYWQgcGFja2FnZXMsIGJ1dCBzbG93IGZvciBCaW5kZXIuCgpsaXN0LmZpbGVzKCJmdW5jdGlvbnMvIiwgcGF0dGVybiA9ICJcXC5SIiwgZnVsbC5uYW1lcyA9IFRSVUUpICU+JQogIHdhbGsoc291cmNlKQpgYGAKCioqTkIgbm90IGFsbCBvZiB0aGUgY2h1bmtzIGJlbG93IHNob3VsZCBiZSBydW4gb24gQmluZGVyIGFzIHNvbWUgb2YgdGhlIGNvZGUgd2lsbCB0YWtlIGEgbG9uZyB0aW1lIG9yIGZhaWwgdG8gZXhlY3V0ZS4qKgoKIyMgR1BsYXRlcyBXZWIgU2VydmljZSAjIwoKR1dTIGNhbiByZWNvbnN0cnVjdCB0aGUgbG9jYXRpb25zIG9mIHBvaW50cywgY29hc3RsaW5lcywgcGxhdGVzLCBwYXRocywgYW5kIGZlYXR1cmVzIGJhY2sgaW50byB0aGUgcGFzdCAoPGh0dHBzOi8vZ2l0aHViLmNvbS9HUGxhdGVzL2dwbGF0ZXNfd2ViX3NlcnZpY2VfZG9jL3dpa2k+KS4gSXQgY2FuIGFsc28gdXNlIGEgdmFyaWV0eSBvZiBkaWZmZXJlbnQgcmVjb25zdHJ1Y3Rpb25zLiBNb3N0IHJlbGV2YW50IGlzIHBlcmhhcHMgdGhlIEBHb2xvbmthMjAwN0cgbW9kZWwsIHdoaWNoIGlzIG9mdGVuIHVzZWQgZm9yIHBhbGFlb2Nvb3JkaW5hdGUgcmVjb25zdHJ1Y3Rpb24gaW4gdGhlIFBhbGFlb2Jpb2xvZ3kgRGF0YWJhc2UgKFBCREIpLgoKVGhlIHByb2Nlc3MgaXM6CgoxLiBEb3dubG9hZCBvdXRsaW5lcyBvZiB0aGUgY29udGluZW50YWwgY29hc3RsaW5lcy4KMi4gRG93bmxvYWQgb3V0bGluZXMgb2YgdGhlIHRlY3RvbmljIHBsYXRlcy4KMy4gUmVhZCBhbmQgY29udmVydCB0aGVzZSBpbnRvIGEgZm9ybWF0IHRoYXQgUiBhbmQgX2dncGxvdDJfIGNhbiB1c2UsCiAgLSB0aGlzIHVzZXMgdGhlIHBhY2thZ2VzIF9yZ2RhbCwgcmVhZHIsXyBhbmQgX2Jyb29tLl8KNC4gUGxvdCwKICAtIGluIHRoaXMgY2FzZSB3aXRoIF9ncHBsb3QuXwoKKipFeGFtcGxlIGNvZGUgb25seS4gRG8gbm90IHJ1bi4qKiBUaGUgY29kZSBiZWxvdyBkb2VzIHRoZXNlIHN0ZXBzIGJ5IGRvd25sb2FkaW5nIHRoZSBkYXRhLCB3aGljaCB3aWxsIGxpa2VseSB0YWtlIHNvbWUgdGltZS4KCmBgYHtyIGd3c19kYXRhLCBldmFsID0gRkFMU0V9CiMjIyMgRE8gTk9UIFJVTiBUSElTIENPREUgIyMjIwpjb2FzdGxpbmVfZ3dzX3VybCA8LQogICJodHRwOi8vZ3dzLmdwbGF0ZXMub3JnL3JlY29uc3RydWN0L2NvYXN0bGluZXMvP3RpbWU9MTU1Jm1vZGVsPUdPTE9OS0EiCnBvbHlnb25zX2d3c191cmwgPC0KICAiaHR0cDovL2d3cy5ncGxhdGVzLm9yZy9yZWNvbnN0cnVjdC9zdGF0aWNfcG9seWdvbnMvP3RpbWU9MTU1Jm1vZGVsPUdPTE9OS0EiCgpraW1tZXJpZGdpYW5fY29hc3RsaW5lcyA8LQogIHJnZGFsOjpyZWFkT0dSKGNvYXN0bGluZV9nd3NfdXJsKSAlPiUKICAgIGJyb29tOjp0aWR5KCkKa2ltbWVyaWRnaWFuX3BvbHlnb25zIDwtCiAgcmdkYWw6OnJlYWRPR1IocG9seWdvbnNfZ3dzX3VybCkgJT4lCiAgICBicm9vbTo6dGlkeSgpCmBgYAoKVGhpcyBjaHVuayBiZWxvdyByZXBsaWNhdGVzIHRoZSBhYm92ZSB1c2luZyBkYXRhIEkndmUgYWxyZWFkeSBkb3dubG9hZGVkIGZyb20gR1dTIGFuZCBzdG9yZWQgaW4gdGhlIEdpdEh1YiByZXBvc2l0b3J5LCBhbmQgY2FuIGJlIHVzZWQgb24gQmluZGVyLiBJdCBoYXMgdGhlIHNhbWUgc3RlcHMgb2YgbG9hZGluZyBhbmQgdGlkeWluZyB0aGUgZGF0YSwgdGhlbiBpbmNsdWRlcyB0aGUgY29tbWFuZHMgdG8gcGxvdCB3aXRoIF9nZ3Bsb3QyLl8KCioqRmVlbCBmcmVlIHRvIHJ1biB0aGlzIGNvZGUuKioKCmBgYHtyIGd3c19wbG90LCBmaWcud2lkdGggPSA3LCBmaWcuaGVpZ2h0ID0gNCwgZmlnLmNhcCA9ICIqKk91dGxpbmVzIG9mIGNvbnRpbmVudGFsIHBsYXRlcyBpbiB0aGUgS2ltbWVyaWRnaWFuICgxNTUgTWEpLioqIFBsYXRlcyBpbiB0aGUgY29udGluZW50YWwgbW9kZWwgYXJlIHNoYWRlZCBncmV5LCB3aGlsZSB0aGUgbW9kZXJuIGNvYXN0bGluZXMgYXJlIG91dGxpbmVkLiBEYXRhIGRvd25sb2FkZWQgZnJvbSB0aGUgR1BsYXRlcyB3ZWIgc2VydmljZS4iLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgcmVzdWx0cyA9ICJoaWRlIn0KIyBMb2FkIGFuZCB0aWR5IHRoZSBkYXRhIApraW1tZXJpZGdpYW5fY29hc3RsaW5lcyA8LQogIHJlYWRPR1IoCiAgICAiZGF0YS9HV1MvTWF0dGhld3NfZXRhbF9HUEdfMjAxNl9Db2FzdGxpbmVzX3JlY29uc3RydWN0ZWRfMTU1LjAwTWEuZ210IgogICkgJT4lCiAgdGlkeSgpCmtpbW1lcmlkZ2lhbl9wb2x5Z29ucyA8LQogIHJlYWRPR1IoCiAgICAiZGF0YS9HV1MvTWF0dGhld3NfZXRhbF9HUEdfMjAxNl9Qb2x5Z29uc19yZWNvbnN0cnVjdGVkXzE1NS4wME1hLmdtdCIKICApICU+JQogIHRpZHkoKQoKZ2dwbG90KCkgKwogIGdlb21fbWFwKAogICAgZGF0YSA9IGtpbW1lcmlkZ2lhbl9wb2x5Z29ucywKICAgIG1hcCA9IGtpbW1lcmlkZ2lhbl9wb2x5Z29ucywKICAgIGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgbWFwX2lkID0gaWQpLAogICAgZmlsbCA9ICIjRDhEOEQ4IgogICkgKwogIGdlb21fbWFwKAogICAgZGF0YSA9IGtpbW1lcmlkZ2lhbl9jb2FzdGxpbmVzLAogICAgbWFwID0ga2ltbWVyaWRnaWFuX2NvYXN0bGluZXMsCiAgICBhZXMoeCA9IGxvbmcsIHkgPSBsYXQsIG1hcF9pZCA9IGlkKSwKICAgIGNvbG91ciA9ICIjMjIyMjIyIiwgZmlsbCA9IE5BLCBzaXplID0gMC4zCiAgKSArCiAgY29vcmRfbWFwKCJtb2xsd2VpZGUiKSArCiAgbWFwX2JvcmRlcigpICsKICB0aGVtZV9tYXAoKQpgYGAKCldoZW4gcGxvdHRpbmcsIHRoZSBkYXRhIGFyZSBhZGRlZCBhcyBsYXllcnMsIGVhY2ggcGxvdHRpbmcgb3ZlciB0aGUgb3RoZXI6IHBsYXRlIHBvbHlnb25zIGF0IHRoZSBib3R0b20gdGhlbiBjb2FzdGxpbmVzIG9uIHRvcC4gSSd2ZSBhbHNvIHNldCB0aGUgbWFwIHByb2plY3Rpb24gdG8gYmUgW01vbGx3ZWlkZV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTW9sbHdlaWRlX3Byb2plY3Rpb24pLCBidXQgeW91IGNhbiBwbGF5IHdpdGggdGhpcyBhbmQgY2hhbmdlIGl0IHRvIG90aGVycyBpbmNsdWRlZCBpbiB0aGUgX21hcHByb2pfIHBhY2thZ2UgZnVuY3Rpb24gW2BtYXBwcm9qZWN0YF0oaHR0cHM6Ly9yZHJyLmlvL2NyYW4vbWFwcHJvai9tYW4vbWFwcHJvamVjdC5odG1sKS4gT3B0aW9ucyBpbmNsdWRlIGAiR2lsYmVydCJgLCBgImZpc2hleWUiYCwgYW5kIGAiaGV4ImAuIChVc2UsIGZvciBleGFtcGxlLCBgY29vcmRfbWFwKCJmaXNoZXllIiwgbiA9IDAuNylgIHRvIGFkZCBleHRyYSBhcmd1bWVudHMuKQoKQWRkaXRpb25hbGx5IEkndmUgYWRkZWQgYSBib3JkZXIgKGBtYXBfYm9yZGVyKClgLCBpbiB0aGUgYGZ1bmN0aW9uc2AgZm9sZGVyKSBhbmQgdXNlZCBhIGJhc2ljIHRoZW1lIChgdGhlbWVfbWFwKClgKSB0byBnZXQgYSBwbGFpbiBiYWNrZ3JvdW5kLgoKIyMgSG93IFIgcGxvdHMgdGhlc2UgbWFwIGRhdGEgIyMKClRoZSBwb3NpdGlvbnMgYW5kIGV4dGVudCBvZiBtYXAgYXJlYXMgZnJvbSBkYXRhIGluIEdQbGF0ZXMgYXJlIHN0b3JlZCBhcyBhIHNlcmllcyBvZiBfcG9seWdvbnMuXyBFYWNoIHJlZ2lvbiBpcyBvdXRsaW5lZCBieSBhIHNlcmllcyBvZiBwb2ludHMgdGhhdCBmb3JtIGEgY2xvc2VkIHNoYXBlLCBmaWxsZWQgd2l0aCBhIHBhcnRpY3VsYXIgY29sb3VyLiBUaGlzIGlzIGV4cG9ydGVkIGZyb20gR1BsYXRlcyBhcyBPR1ItR01UIGZvcm1hdCwgd2l0aCBmaWxlIGV4dGVuc2lvbiBgLmdtdGAsIHdoaWNoIGxpc3RzIGVhY2ggcG9pbnQgdGhhdCBtYXJrcyB0aGUgY29ybmVyIG9mIGEgcG9seWdvbi4gSW4gUiwgX2Jyb29tXyBjb252ZXJ0cyB0aGlzIHRvIGEgdGliYmxlIChzaW1pbGFyIHRvIGEgZGF0YS5mcmFtZSkgdGhhdCBoYXMgdGhlIF94XyBhbmQgX3lfIGxvY2F0aW9ucyBvZiBlYWNoIHBvaW50LCBhbmQgYSBzZXJpZXMgb2YgY29sdW1ucyB0aGF0IGlkZW50aWZ5IHdoaWNoIHBvbHlnb24gdGhhdCBwb2ludCBiZWxvbmdzIHRvLiBUaGVzZSBJRCBjb2x1bW5zIGFyZSBpbXBvcnRhbnQgdG8gbWFrZSBzdXJlIHRoYXQgcG9seWdvbnMgY29udGFpbiB0aGUgY29ycmVjdCBwb2ludHMgYW5kIGFyZSBjbG9zZWQgcHJvcGVybHkuIFdpdGhvdXQgdGhlc2UsIHRoZXJlIHdvdWxkIG9ubHkgYmUgYSBzaW5nbGUgc2hhcGUgdGhhdCB3b3VsZCBzdHJldGNoIGFjcm9zcyB0aGUgd2hvbGUgZ2xvYmUgYW5kIG5vdCBtYWtlIG11Y2ggc2Vuc2UuCgojIyBOb3QgcXVpdGUgcmlnaHQgIyMKCkdXUyBpcyBjb252ZW5pZW50IGZvciBkYXRhIGFuZCBhY2Nlc3MsIGJ1dCB0aGUgcmVzdWx0cyBpbiB0aGUgcGxvdCBhYm92ZSBzaG93IHRoZSBjdXJyZW50IGNvbnRpbmVudGFsIGNvYXN0bGluZXMgYW5kIHRoZSBwbGF0ZXMuIFRoaXMgZG9lcyBub3QgcmVmbGVjdCB0aGUgYW5jaWVudCBjb2FzdGxpbmVzIHRoYXQgd2VyZSByZWFsbHkgYWZ0ZXIuIEFsc28sIG1hbnkgb2YgdGhlIGNvdW50cmllcyBhcmUgY3Jvc3MtY3V0IGJ5IHRoZSBwb2x5Z29ucyB0aGF0IGZvcm0gdGhlIHNlY3Rpb25zIGluIHRoZSBtb2RlbCwgd2hpY2ggYXJlIHVudGlkeSBhbmQgdHlwaWNhbGx5IG5vdCB2aXNpYmxlLgoKV2UgbmVlZCB0byBnbyB0byB0aGUgbmV4dCBsZXZlbDogX3RydWUgcGFsYWVvZ2VvZ3JhcGhpY2FsIHJlY29uc3RydWN0aW9ucy5fIEZvcnR1bmF0ZWx5IEdQbGF0ZXMgb2ZmZXJzIHRoYXQgdG9vLgoKIyMgRXhlcmNpc2VzIDIgIyMKCjEuIEhhdmUgYSBsb29rIGF0IHRoZSBbR1dTIGRvY3VtZW50YXRpb25dKDxodHRwczovL2dpdGh1Yi5jb20vR1BsYXRlcy9ncGxhdGVzX3dlYl9zZXJ2aWNlX2RvYy93aWtpPikuIFdoYXQgYWRkcmVzcyB3b3VsZCB5b3UgdXNlIHRvIGdldCByZWNvbnN0cnVjdGVkIGNvYXN0bGluZXMgaW4gdGhlIGVhcmx5IENhcmJvbmlmZXJvdXMgdXNpbmcgdGhlIEBNYXR0aGV3czIwMTZHUEMgbW9kZWw/CjIuIE9wZW4gYW4gZXhhbXBsZSBvZiB0aGUgT0dSLUdNVCBkYXRhIGZyb20gdGhlIEdXUywgZWl0aGVyIGZyb20gdGhlIGBkYXRhL0dXU2AgZm9sZGVyIG9yIGJ5IGRvd25sb2FkaW5nIGl0LiBDYW4geW91IHNlZSBob3cgdGhlIHBvbHlnb25zIGFyZSBzdG9yZWQ/IEhvdyBhcmUgZGlmZmVyZW50IHBvbHlnb25zIGlkZW50aWZpZWQ/CjMuIE5vdyBsb29rIGF0IHRoZSB0aWRpZWQgdmVyc2lvbiBpbiBSLCBpLmUuIGBraW1tZXJpZGdpYW5fY29hc3RsaW5lc2Agb3IgYGtpbW1lcmlkZ2lhbl9wb2x5Z29uc2AuIEJ5IGRlZmF1bHQgdGhpcyB3aWxsIG9ubHkgc2hvdyB0aGUgZmlyc3QgMTAgcm93cywgYnV0IHlvdSBjYW4gc2VlIG1vcmUgd2l0aCwgZm9yIGV4YW1wbGUsIGBoZWFkKGtpbW1lcmlkZ2lhbl9wb2x5Z29ucywgbiA9IDUwTClgLiBDYW4geW91IHNlZSBob3cgdGhlIE9HUi1HTVQgZGF0YSBpcyB0cmFuc2ZlcnJlZCB0byB0aGlzIHRpZHkgZm9ybWF0Pwo0LiBQbGF5IGFyb3VuZCB3aXRoIHRoZSBpbnB1dHMgdG8gdGhlIHBsb3QgYWJvdmUuIEhvdyBtZXNzeSBvciBjb2xvdXJmdWwgY2FuIHlvdSBtYWtlIHRoaXMgbWFwPyBXaGF0IG9wdGlvbnMgYXJlIHRoZXJlIGluIGB0aGVtZV9tYXAoKWA/IChIaW50OiB1c2UgYD90aGVtZV9tYXBgIHRvIHNlZS4pCgoKIyAnVHJ1ZScgUGFsYWVvZ2VvZ3JhcGhpY2FsIE91dGxpbmVzICMKCkFtb25nIHRoZSBwcm9qZWN0cyBpbmNsdWRlZCB3aXRoIHRoZSBHUGxhdGVzIGRvd25sb2FkIGlzIHRoZSBzZXQgb2YgcGFsYWVvZ2VvZ3JhcGhpY2FsIHJlY29uc3RydWN0aW9ucyBieSBAQ2FvMjAxN0JiIGZvciB0aGUgbGFzdCA0MDIgbXkuIFRoZXNlIGFyZSBiYXNlZCwgYW5kIHNvIHNob3VsZCBhbGlnbiBuaWNlbHksIHdpdGggdGhlIEBHb2xvbmthMjAwN0cgbW9kZWwgdGhhdCBpcyB1c2VkIGZvciBkYXRhIGluIHRoZSBQQkRCLCB3aGljaCB3ZSdsbCBnZXQgdG8gYmVsb3cuIFRoZXNlIGRhdGEgYXJlIGluIGBHUGxhdGVzU2FtcGxlRGF0YS9GZWF0dXJlQ29sbGVjdGlvbnMvUGFsYWVvZ2VvZ3JhcGh5L0dsb2JhbC9gLgoKQENhbzIwMTdCYiB1c2VkIGEgY29tYmluYXRpb24gb2YgcHJldmlvdXMgcGFsYWVvZ2VvZ3JhcGhpY2FsIHJlY29uc3RydWN0aW9ucywgYW5kIHVwZGF0ZWQgdGhlIGNvYXN0bGluZXMsIG1vdW50YWlucywgYW5kIGV4dGVudCBvZiBsYW5kIGFuZCBpY2UgY2FwcyB1c2luZyBvY2N1cnJlbmNlIGRhdGEgZnJvbSB0aGUgUEJEQi4gSW4gYSBmZXcgbG9jYXRpb25zLCB3aGF0IGhhZCBiZWVuIHJlY29uc3RydWN0ZWQgYXMgbGFuZCBwcm9kdWNlZCBtYXJpbmUgZm9zc2lscywgd2hlbiBhY2NvdW50aW5nIGZvciB0aGUgbW92ZW1lbnQgb2YgcGxhdGVzLCBhbmQgdmljZSB2ZXJzYS4KClRoZXNlIHJlY29uc3RydWN0aW9ucyBpbmNsdWRlIGZvdXIgbGF5ZXJzIHRoYXQgaGF2ZSB0aGUgc2VwYXJhdGVkIHBhbGFlb2V2b252aXJvbm1lbnRhbCByZWdpb25zOgoKKiBTaGFsbG93IG1hcmluZTogc2hlbGYgc2Vhcy4KKiBMYW5kOiB0ZXJyZXN0cmlhbCBoYWJpdGF0cyBvdXRsaW5lZCBieSBjb2FzdGxpbmVzLgoqIE1vdW50YWluOiBhcmVhcyBvZiBtb3VudGFpbiBidWlsZGluZyBhbmQgdXBsaWZ0LgoqIEljZSBjYXA6IHBvbGFyIHJlZ2lvbnMgdGhhdCBoYXZlIHN1YnN0YW50aWFsIGV2aWRlbmNlIGZvciBsb25nIHRlcm0gcHJlc2VuY2Ugb2YgaWNlLgoKVGhlc2UgYXJlIGdpdmVuIHRoZSBhYmJyZXZpYXRpb25zICdzbScsICdsJywgJ20nIGFuZCAnaScuIEl0J3Mgd29ydGggbm90aW5nIHRoYXQgdGhlIHdheSB0aGVzZSBhcmUgYnVpbHQgbWVhbnMgdGhhdCB0aGUgbGF5ZXJzIGhhdmUgdG8gYmUgcGxvdHRlZCBpbiB0aGUgb3JkZXIgYWJvdmUg4oCTIHNoYWxsb3cgbWFyaW5lIGZpcnN0LCBpY2UgY2FwIGxhc3QuIFRoZXJlIGFyZSB2YXJpb3VzIGFyZWFzIHRoYXQgb3ZlcmxhcCAoQXVzdHJhbGlhIGVzcGVjaWFsbHkpIHNvIHRoZSBvcmRlciBvZiBvdmVybGF5IGJlY29tZXMgaW1wb3J0YW50IGluIG1ha2luZyB0aGUgY29ycmVjdCBib3VuZGFyaWVzIHZpc2libGUuCgojIyBFeHBvcnQgZnJvbSBHUGxhdGVzICMjCgpUaGUgQENhbzIwMTdCYiByZWNvbnN0cnVjdGlvbnMgYXJlbid0IGF2YWlsYWJsZSBmcm9tIEdXUywgYnV0IGNhbiBiZSBleHBvcnRlZCBmcm9tIEdQbGF0ZXMgZGlyZWN0bHkgdXNpbmcgdGhlIG1lbnUgaXRlbSBfUmVjb25zdHJ1Y3Rpb24gPiBFeHBvcnTigKZfIExpa2UgYWJvdmUgSSd2ZSBhbHJlYWR5IGRvbmUgdGhpcyBmb3IgYW4gZXhhbXBsZSBkYXRhIHNldCwgaW4gdGhpcyBjYXNlIHVzaW5nIHRoZSBMYXRlIEp1cmFzc2ljIChLaW1tZXJpZGdpYW4sIDE1NSBNYSkgYXMgYW4gZXhhbXBsZS4gVG8gbWFrZSB5b3VyIG93biwgb25jZSBpbiB0aGUgZXhwb3J0IHdpbmRvdzoKCjEuIFNlbGVjdCB0aGUgdGltZSBvZiBleHBvcnQgKGNhbiAgYmUgc2V0IGZyb20gdGhlIG1haW4gd2luZG93IHRpbWUpLgogICAgLSBBbHNvIGFuIG9wdGlvbiB0byBleHBvcnQgYSBzZXJpZXMgYXQgcmVndWxhciBpbnRlcnZhbHMuCjIuIFRoZSBsYXllcnMgdG8gZXhwb3J0CiAgICAxLiBzZWxlY3QgX0FkZCBFeHBvcnTigKZfIHVuZGVyIEV4cG9ydCBEYXRhCiAgICAyLiBjaG9vc2UgX1JlY29uc3RydWN0ZWQgR2VvbWV0cmllc18KICAgIDMuIG91dHB1dCBhcyBfT0dSLUdNVF8KICAgIDQuIGNob29zZSBzaW5nbGUgb3IgbXVsdGlwbGUgZmlsZXMKICAgICAgICArIEkgcHJlZmVyIG11bHRpcGxlOiB5b3UgZ2V0IG9uZSBmaWxlIGZvciBlYWNoIG9mIHNlYS9sYW5kL21vdW50YWluL2ljZS4gVGhpcyBpcyB0aGUgZm9ybSB0aGF0IHdvcmtzIHdpdGggdGhlIGNvZGUgYmVsb3cuCiAgICA1LiBfT0tfCjMuIENoYW5nZSBfVGFyZ2V0IGRpcmVjdG9yeTpfIHRvIHNvbWV3aGVyZSB5b3UgY2FuIGZpbmQuCjMuIF9CZWdpbiBFeHBvcnRfCgohW0V4cG9ydCBvcHRpb25zIGZyb20gR1BsYXRlcy5dKC4vZmlncy9ncGxhdGVzX2V4cG9ydDEucG5nKQoKIVtMYXllciBzZWxlY3Rpb24gaW4gR1BsYXRlcyBleHBvcnQuIFNlbGVjdCBSZWNvbnN0cnVjdGVkIGdlb21ldHJpZXMsIE9HUi1HTVQsIGFuZCBtdWx0aXBsZSBsYXllcnMuXSguL2ZpZ3MvZ3BsYXRlc19leHBvcnQyLnBuZykKClRoZSBleGFtcGxlIGRhdGEgYXJlIGluIGBkYXRhL3BhbGFlb2dlb2dyYXBoeWAgYXMgdGhyZWUgYC5nbXRgIGZpbGVzIHRoYXQgZGVzY3JpYmUgdGhlIHBvbHlnb24gb3V0bGluZXMgZm9yIGVhY2ggb2YgdGhlIGxheWVycy4gTm90ZSB0aGF0IGFzIHRoZXJlIGFyZSBubyBpY2UgY2FwcyBhdCB0aGlzIHRpbWUsIHRoZXJlIGFyZSBvbmx5IHRocmVlIGZpbGVzL2xheWVycy4gTG9vayBhdCB0aGUgQ2FyYm9uaWZlcm91cyBvZiBsYXRlciBQYWxhZW9nZW5lIHRvIGdldCBzb21lIGljZSBjYXBzLgoKIyMgUmVhZCBpbiB0aGUgbWFwIGRhdGEgIyMKCkkgZmluZCBpdCB1c2VmdWwgdG8gdGllIHRvZ2V0aGVyIHRoZSBsYXllcnMgYW5kIGNvbG91cnMgZnJvbSB0aGUgYmVnaW5uaW5nIG9mIGltcG9ydGluZyDigJMgdGhpcyBlbnN1cmVzIGtlZXBpbmcgdGhlIGxheWVycyBpbiB0aGUgb3JkZXIgZm9yIHBsb3R0aW5nLiBUaGUgZGF0YSBmaWxlcyBhcmU6CgoqIGBsbV80MDJfMl9yZWNvbnN0cnVjdGVkXzE1NS4wME1hLmdtdGA6IGxhbmRtYXNzCiogYG1fNDAyXzJfcmVjb25zdHJ1Y3RlZF8xNTUuMDBNYS5nbXRgOiBtb3VudGFpbgoqIGBzbV80MDJfMl9yZWNvbnN0cnVjdGVkXzE1NS4wME1hLmdtdGA6IHNoYWxsb3cgbWFyaW5lCgpUaGlzIHNob3J0IGNvZGUgc25pcHBldCBzZXRzIGxpc3RzIHRoZSBsYXllciBuYW1lcyBhbmQgYXNzaWducyB0aGUgY29sb3VycyBmb3IgZWFjaCBsYXllciBvbiB0aGUgbWFwIOKAkyB0aGV5IGFyZSBzaW1pbGFyIHRvIHRob3NlIHNob3duIGluIEdQbGF0ZXMsIGJ1dCBub3QgcXVpdGUgdGhlIHNhbWUuIEkndmUgYWxzbyB1c2VkIGAjREFEM0ZGYCBmb3IgaWNlIGNhcHMgd2hlbiBuZWVkZWQuIChUZWNobmljYWxseSB0aGlzIGlzbid0IHVzZWQgZm9yIHRoZSBjb2xvdXJzLCB0aGF0J3MgaW4gdGhlIGBwYWxhZW9nZW9nX21hcF9uaWNldGllc2AgZnVuY3Rpb24sIHRoaXMgaXMgc29tZXdoYXQgYSByZW1uYW50IG9mIGEgcHJldmlvdXMgd2F5IHRoYXQgSSBtYWRlIHRoaXMuKQoKYGBge3IgbWFwX2xheWVyc30KbWFwX2xheWVycyA8LQogIGMoCiAgICAiTGFuZCIgICAgICAgICAgID0gIiNGRkQyM0EiLAogICAgIk1vdW50YWluIiAgICAgICA9ICIjRkY4RDUxIiwKICAgICJTaGFsbG93IG1hcmluZSIgPSAiIzQ1RDhGRiIKICApCmBgYAoKV2l0aCB0aGF0IHJlYWR5LCB0aGUgZm9sbG93aW5nIGNvZGUgcmVhZHMgYW5kIHRpZGllcyB0aGUgZGF0YSAoYXMgZm9yIGFib3ZlKSwgdGhlbiBhZGRzIGEgY29sdW1uIChnZW9nX2xheWVyKSB0byBpZGVudGlmeSB0aGUgZGF0YSBsYXllciAoc2hhbGxvdyBtYXJpbmUsIGxhbmQsIG1vdW50YWluKSBhbmQgam9pbnMgYWxsIHRoZSBkYXRhIHRvZ2V0aGVyLiBJdCdzIHZlcnkgX3RpZHl2ZXJzZV8gYmFzZWQsIHNvIEknZCBzdWdnZXN0IGxvb2tpbmcgYXQgPGh0dHBzOi8vd3d3LnRpZHl2ZXJzZS5vcmc+IHRvIHNlZSB0aGUgcmF0aW9uYWxlIGFuZCBob3cgdGhleSBsaW5rIHVzaW5nIHRoZSBfcGlwZV8gKGAlPiVgKS4gWW91IGNhbiBhbHNvIHNlZSBtb3JlIGFib3V0IGluZGl2aWR1YWwgZnVuY3Rpb25zIGluIHRoZSBSIGhlbHAuCgpUaGUgZmluYWwgc3RlcCBpcyB0byBjcmVhdGUgYSBjb2x1bW4gKHBvbHlnb25faWQpIHRvIGlkZW50aWZ5IGVhY2ggcmVnaW9uIG9uIHRoZSwgd2hpY2ggY29tZSBhZnRlciBtb3VudGFpbiBtYXAuIEkgaGFkIGEgbG9uZyBpc3N1ZSB3aGVyZSBkaWZmZXJlbnQgY29udGluZW50cyB3b3VsZCBqb2luIHVwLCBvciBBdXN0cmFsaWEncyBsYW5kIHdvdWxkIGFsd2F5cyBhcHBlYXIgcGxvdHRlZCB1bmRlcm5lYXRoIHRoZSBzZWEuIEFzIGRlc2NyaWJlZCBhYm92ZSwgdGhpcyBpcyBiZWNhdXNlIHRoZSBzaGFwZXMgb24gdGhlIG1hcCBhcmUgcGxvdHRlZCBhcyBzZXBhcmF0ZSBwb2x5Z29ucywgYW5kIHRoZSBJRHMgYXJlIHJlcGVhdGVkIGJldHdlZW4gZWFjaCBvZiB0aGUgbGF5ZXJzLiBXZSdsbCB1c2UgdGhlIHBvbHlnb25faWQgY29sdW1uIHRvIG1ha2Ugc3VyZSB0aGF0IGVhY2ggcG9seWdvbiBoYXMgYSB1bmlxdWUgSUQgYnkgam9pbmluZyB0aGUgbGF5ZXIsIGdyb3VwIGFuZCBpZCBuYW1lIGZyb20gdGhlIHRpZGllZCBkYXRhLgoKYGBge3IgcmVhZF9wb2x5Z29uX2RhdGF9CnBvbHlnb25fZGF0YSA8LQogIGxpc3QuZmlsZXMoImRhdGEvcGFsYWVvZ2VvZ3JhcGh5LyIsIHBhdHRlcm4gPSAiLmdtdCIsIGZ1bGwubmFtZXMgPSBUUlVFKSAlPiUKICAgIG1hcChyZWFkT0dSKSAlPiUKICAgIG1hcCh0aWR5KSAlPiUKICAgIG1hcDIoCiAgICAgIG5hbWVzKG1hcF9sYXllcnMpLAogICAgICB+IGFkZF9jb2x1bW4oLngsIGdlb2dfbGF5ZXIgPSAueSkKICAgICkgJT4lCiAgICBiaW5kX3Jvd3MoKSAlPiUKICAgIG11dGF0ZSgKICAgICAgcG9seWdvbl9pZCA9IHN0cl9jKGlkLCBncm91cCwgZ2VvZ19sYXllcikgJT4lIGFzX2ZhY3RvcigpLAogICAgICBnZW9nX2xheWVyID0gZmFjdG9yKGdlb2dfbGF5ZXIsIGxhYmVscyA9IG5hbWVzKG1hcF9sYXllcnMpKQogICAgKQpgYGAKCiMjIEFycmFuZ2luZyB0aGUgbWFwIGxheWVycyAjIwoKQXQgdGhpcyBwb2ludCBpdCdzIGltcG9ydGFudCB0byBoYXZlIHRoZSBtYXAgbGF5ZXJzIGluIHRoZSBjb3JyZWN0IG9yZGVyLCBzbyB0aGF0IG1hcmluZSBpcyBwbG90dGVkIHVuZGVyIGxhbmQsIHdoaWNoIGlzIHBsb3R0ZWQgdW5kZXIgbW91bnRhaW4uCgpUaGlzIHBpZWNlIG9mIGNvZGUgZG9lcyB0aGF0IGZvciB5b3UsIGVuc3VyaW5nIHNoYWxsb3cgbWFyaW5lIGlzIGZpcnN0IChpdCB3YXMgdGhpcmQgaW4gYG1hcF9sYXllcnNgIGFib3ZlKSB0aGVuIGFzc2lnbmluZyB0aGlzIG9yZGVyIHRvIHRoZSBwb2x5Z29uX2lkIGNvbHVtbi4gSXQgY29udmVydHMgdGhlIHBvbHlnb25faWQgY29sdW1uIHRvIGEgZmFjdG9yIGFuZCByZS1vcmRlcnMgdGhlZSBsZXZlbHMgYmFzZWQgb24gdGhlIHJlb3JkZXJlZCBgbWFwX2xheWVyc2AuCgpgYGB7ciByZWFycmFuZ2VfcG9seWdvbl9sYWJlbHN9CmlkX2xldmVsX29yZGVyIDwtCiAgbWFwX2xheWVyc1tjKDMsIDEsIDIpXSAlPiUKICAgIG1hcCgKICAgICAgZnVuY3Rpb24obGF5cikgcG9seWdvbl9kYXRhJHBvbHlnb25faWQgJT4lIGxldmVscygpICU+JSBzdHJfd2hpY2gobGF5cikKICAgICkgJT4lCiAgICB1bmxpc3QoKQoKcG9seWdvbl9kYXRhIDwtCiAgcG9seWdvbl9kYXRhICU+JQogICAgbXV0YXRlKAogICAgICBwb2x5Z29uX2lkID0gZmN0X3JlbGV2ZWwocG9seWdvbl9pZCwgbGV2ZWxzKHBvbHlnb25faWQpW2lkX2xldmVsX29yZGVyXSkKICAgICkKYGBgCgojIyBQbG90dGluZyB0aGUgbWFwICMjCgpVbmZvcnR1bmF0ZWx5LCB1c2luZyB0aGUgc2FtZSBwbG90IGxheWVyIG1ldGhvZCBhcyBmb3IgdGhlIEdXUyBkYXRhIGFib3ZlIGlzIGEgbGl0dGxlIGV4Y2Vzc2l2ZS4gWW91IHdvdWxkIGhhdmUgdG8gYWRkIGEgbmV3IGFubm90YXRpb24gZm9yIGVhY2ggbGF5ZXIgKGp1c3QgYWJvdXQgb2theSBmb3IgdGhyZWUsIHRlZGlvdXMgZm9yIG1vcmUpLCB3aGljaCB0aGVuIG11bHRpcGxpZXMgd2hlbiBwbG90dGluZyByZWNvbnN0cnVjdGlvbnMgb2YgbWFueSB0aW1lcy4KCmBgYHtyIG1hbnlfYW5ub3RhdGlvbnMsIGV2YWwgPSBGQUxTRX0KIyBETyBOT1QgUlVOIFRISVMgQ09ERQpnZ3Bsb3QoKSArCiAgZ2VvbV9tYXAoKSArCiAgZ2VvbV9tYXAoKSArCiAgZ2VvbV9tYXAoKSArIOKApgpgYGAKCkluc3RlYWQsIHlvdSBjYW4gdXNlIHRoZSBmdW5jdGlvbiBgZ2VvbV9wb2x5Z29uYCBhbmQgaGF2ZSB0aGUgZGlmZmVyZW50IGxheWVycyBwbG90dGVkIGF1dG9tYXRpY2FsbHkgd2l0aCB0aGUgY29sb3VycyBhc3NpZ25lZCBhYm92ZS4gVGhlIF9maWxsXyBpcyB0aGUgbW9zdCBpbXBvcnRhbnQgYXJndW1lbnQgYXMgdGhhdCBhc3NpZ25zIHRoZSBtYWluIGJ1bGsgb2YgdGhlIGNvbG91ci4gVGhlIF9jb2xvdXJfIGFyZ3VtZW50IGlzIHRoZSBvdXRsaW5lLCB3aGljaCB5b3Ugc2hvdWxkbid0IHVzZSBiYXMgdGhhdCB3aWxsIG91dGxpbmUgdGhlIG1hcCBsYXllcnMgYW5kIGNoYW5nZSB0aGVpciBzaGFwZS4gVGhlIGBjb2xvdXJgIGFyZ3VtZW50IHdpbGwgYmUgdXNlZCB3aGVuIHBsb3R0aW5nIG9jY3VycmVuY2UgcG9pbnRzIChzZWUgYmVsb3cpLiBBbHNvIGhhdmluZyB0aGUgb3JkZXJlZCBhbmQgY29ycmVjdGx5IGdyb3VwZWQgX3BvbHlnb25faWRfIGlzIGltcG9ydGFudCBoZXJlIGFzIHRoYXQgZGV0ZXJtaW5lcyBob3cgdGhlIGluZGl2aWR1YWwgcG9seWdvbnMgYXJlIGdyb3VwZWQgYW5kIGNsb3NlZCwgcHJldmVudGluZyBzaGFwZXMgZnJvbSBzcGFubmluZyB0aGUgZ2xvYmUsIG9yIGluY29ycmVjdGx5IG92ZXJsYXBwaW5nLgoKSSdsbCBwb2ludCBvdXQgaGVyZSB0aGF0IHRoZXJlJ3MgcXVpdGUgYSBsb3QgZ29pbmcgb24gaW4gdGhlIGBwYWxhZW9nZW9nX21hcF9uaWNldGllc2AgZnVuY3Rpb24gYXQgdGhlIGVuZC4gVGhpcyBpcyBhIGNvbGxlY3Rpb24gb2YgdGhlbWUgb3B0aW9ucyBhbmQgYSBjb2xvdXIgc2NhbGUgdG8gc2hvdyB0aGUgbWFwIHByb3Blcmx5LiBJbiBwYXJ0aWN1bGFyIHRoaXMgYWRkcyB0aGUgb3V0bGluZSBhbmQgdGhlIGxpbmVzIG9mIHRoZSBlcXVhdG9yIGFuZCB0cm9waWNzLiBJIGd1ZXNzIG9uZSB0aGluZyB0byBub3RlIGlzIHRoYXQgdGhlICd0cm9waWNzJywgaW4gYSBiaW9kaXZlcnNpdHkgc2Vuc2UsIG1heSBub3QgYmUgdGhlIHNhbWUgaW4gdGhlIHBhc3QgYXMgdGhlIHByZXNlbnQuIEluY3JlYXNlZCB0ZW1wZXJhdHVyZXMgY2FuIGNoYW5nZSB0aGUgbGF0aXR1ZGluYWwgYmlvZGl2ZXJzaXR5IGdyYWRpZW50LiBBbHNvLCBvYmxpcXVpdHkgYW5kIHByZWNlc3Npb24gY2hhbmdlIHRoZSBsYXRpdHVkZXMgb2YgdGhlIGFzdHJvbm9taWNhbCB0cm9waWNzIHRocm91Z2ggdGltZS4KCmBgYHtyIHBsb3RfYmFzZV9tYXAsIGZpZy53aWR0aCA9IDcsIGZpZy5oZWlnaHQgPSA0LCBmaWcuY2FwID0gIioqUGFsYWVvZ2VvZ3JhcGh5IGluIHRoZSBLaW1tZXJpZGdpYW4gKDE1NSBNYSkuKiogUGFsYWVvZ2VvZ3JhcGhpY2FsIHJlY29uc3RydWN0aW9uIGZyb20gQENhbzIwMTdCYi4gTGluZXMgb2YgbGF0aXR1ZGUgaW5kaWNhdGUgdGhlIGxvY2F0aW9ucyBvZiB0aGUgRXF1YXRvciBhbmQgVHJvcGljcyAowrEyMy41wrApLiJ9CiMgZGV2Lm5ldyh3aWR0aCA9IDcsIGhlaWdodCA9IDQpCm1hcF9wbG90IDwtCiAgZ2dwbG90KCkgKwogICAgZ2VvbV9wb2x5Z29uKAogICAgICBkYXRhID0gcG9seWdvbl9kYXRhLAogICAgICBhZXMoCiAgICAgICAgeCAgICAgID0gbG9uZywKICAgICAgICB5ICAgICAgPSBsYXQsCiAgICAgICAgZmlsbCAgID0gZ2VvZ19sYXllciwKICAgICAgICBncm91cCAgPSBwb2x5Z29uX2lkCiAgICAgICksCiAgICAgIGNvbG91ciA9IE5BCiAgICApICsKICAgIGNvb3JkX21hcCgibW9sbHdlaWRlIikgKwogICAgdGhlbWVfbWFwKCkgKwogICAgcGFsYWVvZ2VvZ19tYXBfbmljZXRpZXMoKQptYXBfcGxvdApgYGAKCllvdSBjYW4gdHJ5IGNoYW5naW5nIHRoZSBsb29rIGJ5IG1vZGlmeWluZyB0aGUgcHJvamVjdGlvbiAoYGNvb3JkX21hcGApIGFuZCBwbGF5IGFib3V0IHdpdGggc29tZSBvZiB0aGUgY29sb3VycyBhbmQgbWFya2luZ3MgYnkgZWRpdGluZyB0aGUgZnVuY3Rpb24gYHBhbGFlb2dlb2dfbWFwX25pY2V0aWVzYCAoYGZ1bmN0aW9ucy9wYWxhZW9nZW9nX21hcF9uaWNldGllcy5SYCkuIFlvdSBjYW4gYWxzbyBhZGQgZnVydGhlciBhbm5vdGF0aW9ucyAoPGh0dHBzOi8vZ2dwbG90Mi1ib29rLm9yZy9hbm5vdGF0aW9ucy5odG1sI2Fubm90YXRpb25zPikgb3IgY2hhbmdlIGxhYmVscyBhcyB5b3Ugd2lzaC4KCiMjIEdvaW5nIGZ1cnRoZXIgMTogbG9jYXRpbmcgd2l0aCBtb2Rlcm4gY29hc3RsaW5lcyAjIwoKWW91IG1heSBhbHNvIHdhbnQgdG8gYWRkIG91dGxpbmVzIG9mIG1vZGVybiBjb2FzdGxpbmVzIHRvIHNob3cgd2hlcmUgdGhlc2UgYXJlIGFuZCBoZWxwIGxvY2F0aW5nLiBBZ2FpbiB0aGVzZSBhcmUgbm90IGF2YWlsYWJsZSBmcm9tIEdXUywgYnV0IGNhbiBiZSBleHBvcnRlZCBmcm9tIEdQbGF0ZXMuIEluIEdQbGF0ZXMsIGZyb20gX0ZpbGUgPiBPcGVuIEZlYXR1cmUgQ29sbGVjdGlvbuKApl8gZ28gdG8gYEdwbGF0ZXNTYW1wbGVEYXRhL0ZlYXR1cmVDb2xsZWN0aW9ucy9Db2FzdGxpbmVzYCBhbmQgbG9hZCBgTWF0dGhld3NfZXRhbF9HUENfMjAxNl9Db2FzdGxpbmVzX1BvbHlsaW5lLmdwbWx6YC4gVGhpcyBhZGRzIGEgbmV3IGxheWVyIGludG8gR1BsYXRlcyB3aXRoIGFyZWFzIG9mIG1vZGVybiBjb2FzdGxpbmUgaW4gdGhlaXIgcmVsYXRpdmUgcG9zaXRpb25zIGZvciB0aGUgdGltZS4gTm90IGFsbCB0aGUgbW9kZXJuIGNvYXN0bGluZXMgYXJlIHRoZXJlIGFzIG5vdCBhbGwgb2YgdGhlc2UgaGF2ZSBjZXJ0YWluIGxvY2F0aW9ucywgb3Igcm9jayB0byBiZSBmb3VuZCBhdCDigJMgdGhlc2UgY29tZSBhbmQgZ28gYXQgZGlmZmVyZW50IHRpbWUgcG9pbnRzLgoKTGlrZSBhYm92ZSwgeW91IGNhbiBleHBvcnQgdGhpcyBsYXllciBmcm9tIEdQbGF0ZXMuIEluIHRoaXMgcmVwbywgSSd2ZSBhbHJlYWR5IGRvbmUgdGhhdCB0byBgZGF0YS9jb2FzdGxpbmVzL2AsIHdoaWNoIHlvdSBjYW4gbG9hZCB3aXRoIHRoaXMgY29kZS4KCmBgYHtyIHJlYWRfY29hc3RsaW5lX3BvbHlnb25zLCByZXN1bHRzID0gImhpZGUifQptb2Rlcm5fY29hc3RsaW5lcyA8LQogIHJlYWRPR1IoImRhdGEvY29hc3RsaW5lcy9NYXR0aGV3c19ldGFsX0dQQ18yMDE2X0NvYXN0bGluZXNfUG9seWxpbmVfcmVjb25zdHJ1Y3RlZF8xNTUuMDBNYS5nbXQiKSAlPiUKICAgIHRpZHkoKSAlPiUKICAgIGFkZF9jb2x1bW4oZ2VvZ19sYXllciA9ICJNb2Rlcm4gY29hc3RsaW5lcyIpICU+JQogICAgbXV0YXRlKHBvbHlnb25faWQgPSBzdHJfYyhpZCwgZ3JvdXAsIGdlb2dfbGF5ZXIpICU+JSBhc19mYWN0b3IoKSkKYGBgCgpUaGlzIGxheWVyIG5lZWRzIHRoZSBzYW1lIG9yZ2FuaXNpbmcgb2YgSURzIGFzIHRoZSBwYWxhZW9nZW9ncmFwaHkgYWJvdmUsIGJ1dCBvbmNlIGRvbmUgY2FuIGJlIGVhc2lseSBhZGRlZCB0byBgbWFwX3Bsb3RgIGFib3ZlLiBUaGlzIGlzIHdoZXJlIGl0J3MgdXNlZnVsIHRvIHNhdmUgeW91ciBnZ3Bsb3QgdG8gYW4gb2JqZWN0IGFsb25nc2lkZSBwcmludGluZyBpdCDigJMgdGhpcyB5b3UgY2FuIGp1c3QgYWRkIG5ldyBsYXllcnMgb24gdG9wIG9mIHRoZSBiYXNlIG1hcC4KCmBgYHtyIHBsb3RfY29hc3Rfb3V0bGluZXMsIGZpZy53aWR0aCA9IDcsIGZpZy5oZWlnaHQgPSA0LCBmaWcuY2FwID0gIioqUGFsYWVvZ2VvZ3JhcGh5IGluIHRoZSBLaW1tZXJpZGdpYW4gKDE1NSBNYSkuKiogT3V0bGluZXMgb2YgbW9kZXJuIGNvYXN0bGluZXMgKHdoZXJlIGtub3duKSBhcmUgaW5jbHVkZWQgaW4gZ3JleS4gUGFsYWVvZ2VvZ3JhcGhpY2FsIHJlY29uc3RydWN0aW9uIGZyb20gQENhbzIwMTdCYi4gTGluZXMgb2YgbGF0aXR1ZGUgaW5kaWNhdGUgdGhlIGxvY2F0aW9ucyBvZiB0aGUgRXF1YXRvciBhbmQgVHJvcGljcyAowrEyMy41wrApLiJ9Cm1hcF9wbG90ICsKICBnZW9tX3BhdGgoCiAgICBkYXRhID0gbW9kZXJuX2NvYXN0bGluZXMsCiAgICBhZXMoCiAgICAgIHggPSBsb25nLAogICAgICB5ID0gbGF0LAogICAgICBncm91cCA9IHBvbHlnb25faWQsCiAgICApLAogICAgY29sb3VyID0gIiM4ODg4ODgiLCBzaXplID0gMC4zCiAgKQpgYGAKCiMjIEV4ZXJjaXNlcyAzICMjCgoxLiBUcnkgcGxvdHRpbmcgdGhpcyBtYXAgd2l0aCBkaWZmZXJlbnQgcHJvamVjdGlvbnMgKHNlZSBhYm92ZSBhbmQgYD9tYXBwcm9qZWN0YCkuIERvZXMgdGhpcyB3b3JrIHdlbGwgZm9yIGFsbCBwcm9qZWN0aW9ucz8gV2h5PwoyLiBMb29rIGF0IHRoZSBjb2RlIGJlaGluZCBgcGFsYWVvZ2VvZ19tYXBfbmljZXRpZXMoKWAgKGluIGBmdW5jdGlvbnMvcGFsYWVvZ2VvZ19tYXBfbmljZXRpZXMuUmApLiBNb2RpZnkgdGhpcyB0byBhZGQgZGlmZmVyZW50IGxpbmVzIG9mIGxhdGl0dWRlLiBDYW4geW91IGFkZCBsaW5lcyBvZiBsb25naXR1ZGUgdG9vPyBXaGF0IGFib3V0IGNoYW5naW5nIHRoZSBjb2xvdXI/CiAgLSBfZ2dwbG90XyBvYmplY3RzIGNhbiBoYXZlIG5ldyBsYXllcnMgYWRkZWQgdG8gdGhlbSBvbmUtYnktb25lIGJ5IHVzaW5nIGArYCwgYnV0IHlvdSBjYW4gYWxzbyBjb21iaW5lIHRoZW0gaW50byBmdW5jdGlvbiBjb250YWluaW5nIGEgbGlzdCBvZiBsYXllcnMgdGhhdCBjYW4gYmUgYWRkZWQgaW4gYSBzaW5nbGUgbGluZS4KICAtIEhpbnQ6IHRvIGNoYW5nZSB0aGUgY29sb3VyIG9mIHRoZSBtYXAgbGF5ZXJzLCB1c2UgYGZpbGxgLgozLiBDYW4geW91IHRyeSBjcmVhdGluZyB5b3VyIG93biBwYWxhZW9nZW9ncmFwaGljYWwgbWFwIGZvciB5b3VyIGZhdm91cml0ZSB0aW1lPyBUaGlzIHNob3VsZCBiZSBkb25lIG9uIHlvdXIgb3duIGNvbXB1dGVyLiBGb2xsb3cgdGhlIGluc3RydWN0aW9ucyBhYm92ZSB0byBleHBvcnQgZGF0YSBmcm9tIEdQbGF0ZXMgdGhlbiBwbG90IGluIFIsIG1ha2luZyBzdXJlIHlvdSBjaGFuZ2UgYWxsIHRoZSBmaWxlIGFuZCBvYmplY3QgbmFtZXMuCgoKIyBBZGRpbmcgRm9zc2lsIE9jY3VycmVuY2VzICMKCiMjIEdldHRpbmcgb2NjdXJyZW5jZSBkYXRhICMjCgpOb3cgdGhhdCB5b3UndmUgc3BlbnQgbG90cyBvZiB0aW1lIG1ha2luZyBhIHByZXR0eSBtYXAsIGxldCdzIHBsb3Qgc29tZSBmb3NzaWxzIG9uIHRvcCBvZiBpdC4KCk9mIGNvdXJzZSwgYmVpbmcgbWUgYW5kIGhhdmluZyB1c2VkIEp1cmFzc2ljIGRhdGEsIHdlJ3JlIGdvaW5nIHRvIHBsb3Qgc29tZSBpY2h0aHlvc2F1cnMuIEluIHRoaXMgaW5zdGFuY2UsIHRoZSBvY2N1cnJlbmNlIGRhdGEgY29tZXMgZnJvbSB0aGUgUEJEQiwgZG93bmxvYWRpbmcgaWNodGh5b3NhdXIgb2NjdXJyZW5jZXMgd2l0aCB0aGVzZSBmaWx0ZXJzOgoKLSBDYWxsb3ZpYW7igJNUaXRob25pYW4gKDE2Ni0xNDUgTWEpCi0gYWxsIGxldmVscyBvZiB0YXhvbm9teSDigJMgbm8gZmlsdGVyaW5nLgoKVGhlIFBCREIgaGFzIGl0cyBvd24gd2ViIEFQSSAoPGh0dHBzOi8vcGFsZW9iaW9kYi5vcmcvZGF0YTEuMj4pIGZyb20gd2hpY2ggeW91IGNhbiBnZXQgb2NjdXJyZW5jZXMsIGNvbGxlY3Rpb25zLCB0YXhvbm9teSBhbmQgb3RoZXIgdGhpbmdzLiBJbiB0aGUgY29kZSBjaHVuayBiZWxvdyBJJ3ZlIGNyYWZ0ZWQgdGhlIFVSTCB0byBkb3dubG9hZCB0aGUgZGF0YSwgYnV0IHRoaXMgaXMgYWxyZWFkeSBpbiB0aGUgcmVwbyBzbyBkb2Vzbid0IG5lZWQgdG8gYmUgcnVuLgoKKipEbyBub3QgcnVuIHRoZSBmb2xsb3dpbmcgY2h1bmssIHRoZSBkYXRhIGlzIGFscmVhZHkgaW4gdGhlIHJlcG8uKioKCmBgYHtyIGRvd25sb2FkX3BiZGJfZGF0YSwgZXZhbCA9IEZBTFNFfQojIyMjIERPIE5PVCBSVU4gVEhJUyBDSFVOSyAjIyMjCnBiZGJfdXJsIDwtCiAgImh0dHBzOi8vcGFsZW9iaW9kYi5vcmcvZGF0YTEuMi9vY2NzL2xpc3QuY3N2P2Jhc2VfbmFtZT1JY2h0aHlvc2F1cm9tb3JwaGEmaW50ZXJ2YWw9Q2FsbG92aWFuLE94Zm9yZGlhbixLaW1tZXJpZGdpYW4sVGl0aG9uaWFuJnNob3c9cGFsZW9sb2MiCgpvY2NfaWNodGh5b3NhdXJzIDwtCiAgcmVhZF9jc3YocGJkYl91cmwpCmBgYAoKVGhlIHBhcnQgb2YgdGhlIFVSTCBgc2hvdz1wYWxlb2xvY2AgaXMgdGhlIGltcG9ydGFudCBiaXQgYXMgdGhlIFBCREIgaGFzIGFscmVhZHkgY29tcHV0ZWQgdGhlIHBhbGFlb2Nvb3JkaW5hdGVzIG9mIG1vc3Qgb2NjdXJyZW5jZXMgdXNpbmcgdGhlaXIgbW9kZXJuIGxvY2F0aW9uIGFuZCB0aGUgYWdlcyBvZiB0aGUgb2NjdXJyZW5jZXMuIENvbnZlbmllbnRseSB1c2luZyB0aGUgc2FtZSBkZWZhdWx0IEdQbGF0ZXMgbW9kZWwgYXMgdGhlIHBhbGFlb2dlb2dyYXBoeS4KCiMjIFBsb3R0aW5nIG9jY3VycmVuY2VzICMjCgpXaXRoIHRoYXQgYWxsIGRvbmUsIHVzZSB0aGUgY2h1bmsgYmVsb3cgdG8gYWRkIHRoZSBvY2N1cnJlbmNlcyBvbnRvIHRoZSBiYXNlIG1hcC4gVGhlc2UgYXJlIHBsb3R0ZWQgd2l0aCBgZ2VvbV9wb2ludCgpYCwgd2hpY2ggeW91IG1heSBiZSBmYW1pbGlhciB3aXRoLCBzZXR0aW5nIHRoZSBfeF8gYW5kIF95XyB2YWx1ZXMgdG8gdGhlIHBhbGFlb2xvbmdpdHVkZSBhbmQgcGFsYWVvbGF0aXR1ZGUgcmVzcGVjdGl2ZWx5LgoKYGBge3IgcGxvdF9vY2N1cnJlbmNlcywgZmlnLmhlaWdodCA9IDQsIGZpZy53aWR0aCA9IDcsIGZpZy5jYXAgPSAiKipPY2N1cnJlbmNlcyBvZiBpY2h0aHlvc2F1cnMgZnJvbSB0aGUgQ2FsbG92aWFu4oCTVGl0aG9uaWFuLioqIFBhbGFlb2dlb2dyYXBoaWNhbCBtYXAgc2hvd3MgdGhlIGRpc3RyaWJ1dGlvbiBvZiBsYW5kIGluIHRoZSBLaW1tZXJpZGdpYW4gKDE1NSBNYSkgcmVjb25zdHJ1Y3RlZCBieSBAQ2FvMjAxN0JiLiBPY2N1cnJlbmNlcyBvZiBJY2h0aHlvc2F1cm9tb3JwaGEgYXJlIGZyb20gdGhlIFBhbGFlb2Jpb2xvZ3kgRGF0YWJhc2UuIiwgd2FybmluZyA9IEZBTFNFfQpvY2NfaWNodGh5b3NhdXJzIDwtCiAgcmVhZF9jc3YoImRhdGEvb2NjdXJyZW5jZXMvMjAyMS0wMi0xOC1pY2h0aHlvc2F1ci1vY2N1cnJlbmNlcy5jc3YiKQpvY2NfcGxvdCA8LQogIG1hcF9wbG90ICsKICAgIGdlb21fcG9pbnQoCiAgICAgIGRhdGEgPSBvY2NfaWNodGh5b3NhdXJzLAogICAgICBhZXMoCiAgICAgICAgeCA9IHBhbGVvbG5nLAogICAgICAgIHkgPSBwYWxlb2xhdAogICAgICApCiAgICApCm9jY19wbG90CmBgYAoKVGhlIG1vcmUgZWFnbGUtZXllZCBvZiB5b3UgbWF5IG5vdGljZSB0aGF0IHNvbWUgb2YgdGhlc2UgX21hcmluZV8gaWNodGh5b3NhdXIgb2NjdXJyZW5jZXMgYXJlIGxvY2F0ZWQgcmVzb2x1dGVseSBpbiB0aGUgbWlkZGxlIG9mIGxhbmRtYXNzZXMuIFRoZXJlIGFyZSBhIGZldyBwb3NzaWJsZSByZWFzb25zIGZvciB0aGF0OgoKMS4gVGhlIHBhbGFlb2dlb2dyYXBoaWNhbCByZWNvbnN0cnVjdGlvbiBpcyB3cm9uZy4KMi4gVGhlIG1vZGVybiBsb2NhdGlvbiBmb3IgdGhlIG9jY3VycmVuY2UgaXMgd3JvbmcsIHNvIHRoZSBwYWxhZW9jb29yZGluYXRlcyBhcmUgd3JvbmcuCjMuIFRoZSBhZ2Ugb2YgdGhlIG9jY3VycmVuY2UgaXMgd3JvbmcsIHNvIGl0cyByZWNvbnN0cnVjdGVkIHBvc2l0aW9uIGlzIHdyb25nLgoKVGhlc2UgdGhyZWUgYXJlIHdvcnRoIGNvbnNpZGVyaW5nIGZ1cnRoZXIuIAoKX0luY29ycmVjdCBwYWxhZW9nZW9ncmFwaGljYWwgcmVjb25zdHJ1Y3Rpb25fIGlzIHBlcmhhcHMgdGhlIG1vc3Qgb2J2aW91cyBhbnN3ZXI6IHRoZXNlIHJlY29uc3RydWN0aW9ucyBhcmUgZGlmZmljdWx0IGFuZCB0aGVyZSB3aWxsIGFsd2F5cyBiZSBzb21lIHVuY2VydGFpbnR5IHdpdGggcmVjb25zdHJ1Y3RpbmcgdGhlIGVhcnRoIDE1NSBtaWxsaW9uIHllYXJzIGFnby4gSG93ZXZlciwgdGhlIG1ldGhvZCBvZiBAQ2FvMjAxN0JiIGluY2x1ZGVkIHBhbGFlb2Vudmlyb25tZW50cyByZWNvbnN0cnVjdGVkIHVzaW5nIFBCREIgZGF0YSB0byBpbXByb3ZlIGNvbmZpZGVuY2UgaW4gdGhlIGJvcmRlcnMgb2Ygc2VhIGFuZCBsYW5kLiBUaGUgcGFsYWVvZ2VvZ3JhcGh5IHNob3VsZCBtYXRjaCB0aGUgUEJEQiB3ZWxsIHRoZW4sIHBhcnRpY3VsYXJseSBpbiB3ZWxsLXN0dWRpZWQgYW5kIHNhbXBsZWQgcGVyaW9kcyBhbmQgbG9jYXRpb25zLiBUaGVyZSBhcmUsIGhvd2V2ZXIsIHNvbWUgcGFydHMgdGhhdCBjYW5ub3QgY2VydGFpbmx5IHJlY29uc3RydWN0ZWQgYmVjYXVzZSBvZiBhIGxhY2sgb2YgZGF0YSwgcm9jayBhdmFpbGFiaWxpdHksIG9yIGFjY2Vzc2liaWxpdHkuCgpfSW5jb3JyZWN0IG1vZGVybiBsb2NhdGlvbl8gbWF5IGJlIHRoZSBlYXNpZXN0IHRvIGRpc2NvdW50IGFzIGxvY2FsaXRpZXMgdGVuZCB0byBiZSBzcGF0aWFsbHkgY29uc3RyYWluZWQgYW5kIGlkZW50aWZpYWJsZSwgZXZlbiBpbiBvbGRlciBsaXRlcmF0dXJlLiBUaGlzIGJlaW5nIHRoZSBjYXNlLCB0aGVyZSBzaG91bGQgb25seSBiZSBtaW5vciBlcnJvciBpbiB0aGUgbG9jYXRpb25zIG9mIG9jY3VycmVuY2VzICh+MTBzIGttKS4KCl9JbmNvcnJlY3QgYWdlIGFzc2lnbm1lbnRfIGlzIHByb2JhYmx5IHRoZSBtb3N0IGxpa2VseSBjYXVzZSwgb3IgcGVyaGFwcyBiZXR0ZXIgX2ltcHJlY2lzZV8gYWdlcy4gVGhlIHBhbGFlb2Nvb3JkaW5hdGVzIGNhbGN1bGF0ZWQgZm9yIGVhY2ggb2NjdXJyZW5jZSBpbiB0aGUgUEJEQiB1c2UgdGhlIG1pZHBvaW50IG9mIGl0cyB0ZW1wb3JhbCByYW5nZS4gU29tZXRpbWVzIHRoaXMgcmFuZ2UgY2FuIGJlIHF1aXRlIGxhcmdlLCBzdWNoIGFzIHRoZSBzZXZlcmFsIHNwZWNpZXMgb2YgX1VuZG9yb3NhdXJ1c18gdGhhdCBjb3ZlciB0aGUgd2hvbGUgTGF0ZSBKdXJhc3NpYyAoMTYzLjXigJMxNDUgTWEgaW4gW0dUUyAyMDIwLzAzXShodHRwczovL3N0cmF0aWdyYXBoeS5vcmcvSUNTY2hhcnQvQ2hyb25vc3RyYXRDaGFydDIwMjAtMDMucGRmKSkuIFRob3NlIHNwZWNpbWVucyBmcm9tIFBhdGFnb25pYSB0aGF0IGFyZSBwbG90dGVkIGluIHRoZSBtaWRkbGUgb2YgdGhlIGxhbmQgYXJlIGFsc28gc2ltaWxhcmx5IGltcHJlY2lzZWx5IGRhdGVkLiBUaGVpciBwYWxhZW9jb29yZGluYXRlcyBhcmUgcmVjb25zdHJ1Y3RlZCB0byB0aGUgbWlkZGxlIEtpbW1lcmlkZ2lhbiwgd2hlcmVhcyB0aGV5IGFyZSBsaWtlbHkgbGF0ZXIgKGdpdmVuIHRoZSBvY2N1cnJlbmNlIG9mIGljaHRoeW9zYXVycyBmcm9tIHNpbWlsYXIgbG9jYXRpb25zKSB3aGVuIHRoZXJlIHdhcyBhIHNlYSB0aGVyZSB0byBzd2ltIGluLgoKQXMgdGhlIGljaHRoeW9zYXVyIG9jY3VycmVuY2VzIGluY2x1ZGVkIG92ZXIgb3ZlciAyMCBteSBvZiBlYXJ0aCBoaXN0b3J5IHRoZXJlIHdpbGwgYmUgY2hhbmdlcyBpbiBwYWxhZW9nZW9ncmFwaHksIGFuZCBzb21lIHBvdGVudGlhbGx5IGltcHJlY2lzZSBkYXRpbmcuCgpUaGUgd2F5cyBhcm91bmQgdGhpcyBhcmUgdG8gaGF2ZSBtb3JlIHRpbWUgc2xpY2VzIHdpdGggdGhlIG9jY3VycmVuY2VzIHBsb3R0ZWQsIGJ1dCB0aGlzIGNvbXBsaWNhdGVzIHRoZSBjb2RlIGFuZCBhbnkgcGxvdHMsIGFuZCBzdWNoIHByZWNpc2UgcmVjb25zdHJ1Y3Rpb25zIG1heSBub3QgYmUgYXZhaWxhYmxlLiBBbHRlcm5hdGl2ZWx5LCBhaW0gdG8gdXNlIG9ubHkgdGhlIG1vc3QgcHJlY2lzZWx5IGRhdGVkIG9jY3VycmVuY2VzLCBpZiBwb3NzaWJsZSwgYnV0IHRoaXMgY2FuIHJlbW92ZSBsb3RzIG9mIHVzZWZ1bCBkYXRhLiBVbHRpbWF0ZWx5LCB5b3UgbWF5IGp1c3QgaGF2ZSB0byBhY2NlcHQgdGhhdCBzb21lIG1hcmluZSBvY2N1cnJlbmNlcyBtYXkgYXBwZWFyIG9uIGxhbmQsIG9yIHZpY2UgdmVyc2EuCgojIyBHb2luZyBmdXJ0aGVyIDI6IHNlcGFyYXRpbmcgb2NjdXJyZW5jZXMgd2l0aCBmYWNldHMgIyMKClRoZSBmaW5hbCB0aGluZyB0aGF0IHlvdSBjYW4gdHJ5IGlzIHRoZSBfZmFjZXRpbmdfIHBvd2VyIG9mIF9nZ3Bsb3QyXyB0byBzZXBhcmF0ZSB0aGUgZGlmZmVyZW50IGdyb3VwcyBvZiBvY2N1cnJlbmNlcy4gQmVsb3csIHRoaXMgY29kZSBzcGxpdHMgb3V0IHRoZSBvY2N1cnJlbmNlcyBieSB0aGVpciBhY2NlcHRlZCB0YXhvbm9taWMgcmFuay4gTW9zdCBvY2N1cnJlbmNlcyBhcmUganVzdCBub24tZGlhZ25vc3RpYyB2ZXJ0ZWJyYWwgbWF0ZXJpYWwsIHNvIGNhbid0IGJlIGFzc2lnbmVkIHRvIGEgZmFtaWx5LCBnZW51cyBvciBzcGVjaWVzLiBUaGVzZSBhcmUgbGlzdGVkIHVuZGVyICd1bnJhbmtlZF9jbGFkZScuCgpDb252ZW5pZW50bHksIGNyZWF0aW5nIGZhY2V0cyBpcyBhcyBzaW1wbGUgYXMgYWRkaW5nIGEgc2luZ2xlIGxpbmUuCgpgYGB7ciBmYWNldF9wbG90LCBmaWcud2lkdGggPSA3LCBmaWcuaGVpZ2h0ID0gMTQsIGZpZy5jYXAgPSAiKipPY2N1cnJlbmNlcyBvZiBpY2h0aHlvc2F1cnMgaW4gdGhlIENhbGxvdmlhbuKAk1RpdGhvbmlhbiBzZXBhcmF0ZWQgYnkgaWRlbnRpZmllZCByYW5rLioqIFBhbGFlb2dlb2dyYXBoaWNhbCBtYXBzIHNob3dzIGRpc3RyaWJ1dGlvbiBvZiBsYW5kIGluIHRoZSBLaW1tZXJpZGdpYW4gKDE1NSBNYSkgcmVjb25zdHJ1Y3RlZCBieSBAQ2FvMjAxN0JiLiIsIHdhcm5pbmcgPSBGQUxTRX0Kb2NjX3Bsb3QgKwogIGZhY2V0X3dyYXAodmFycyhhY2NlcHRlZF9yYW5rKSwgbmNvbCA9IDEpCmBgYAoKIyMgRXhlcmNpc2VzIDQgIyMKCjEuIExvb2sgYXQgdGhlIFBCREIgd2ViIEFQSSAoPGh0dHBzOi8vcGFsZW9iaW9kYi5vcmcvZGF0YTEuMj4pLiBXaGF0IG90aGVyIG9wdGlvbnMgYW5kIGRhdGEgc2V0cyBjYW4geW91IGFjY2VzcyB3aXRoIHRoaXM/IENhbiB5b3UgY3JhZnQgYSBVUkwgdGhhdCB3aWxsIGRvd25sb2FkIG9jY3VycmVuY2UgZGF0YSBvZiBUaXRob25pYW4gYml2YWx2ZXMuCiAgLSBUaGlzIGRvd25sb2FkIG1heSBub3Qgd29yayBvbiBCaW5kZXIsIHNvIHlvdSBzaG91bGQgZG8gaXQgaW4gUiBvbiB5b3VyIG93biBjb21wdXRlci4KMi4gVHJ5IGFkZGluZyBjb2xvdXIgb3Igc2hhcGVzIHRvIHlvdSBvY2N1cnJlbmNlIHBvaW50cyB1c2luZyB0aGUgb3B0aW9ucyBpbiBgZ2VvbV9wb2ludGAuCjMuIERvd25sb2FkIGFuZCBwbG90IHRoZSBwYWxhZW9nZW9ncmFwaGljYWwgbWFwIGFuZCBvY2N1cnJlbmNlcyBmb3IgeW91ciBmYXZvdXJpdGUgZ3JvdXAgaW4geW91ciBmYXZvdXJpdGUgc3RhZ2UuIEFnYWluIHRoaXMgc2hvdWxkIGJlIGRvbmUgb24geW91ciBvd24gY29tcHV0ZXIuIEJld2FyZSBpdCBtYXkgdGFrZSBhIHdoaWxlIGlmIHlvdSB3YW50IHRvIHBsb3QgbWFueSBvY2N1cnJlbmNlcy4KNC4gSXQncyBhbHNvIHVzZWZ1bCB0byBzZXBhcmF0ZSBvdXQgb2NjdXJyZW5jZXMgb24gdGhlIG1hcCwgZm9yIGluc3RhbmNlLCBjYW4geW91IGNvbG91ciBvY2N1cnJlbmNlcyB3aXRoaW4gdGhlIG91dHNpZGUgdGhlIHRyb3BpY3MgZGlmZmVyZW50bHk/IHNheSByZWQgaW4gdGhlIHRyb3BpY3MgKMKxMjMuNcKwKSBhbmQgYmx1ZSBvdXRzaWRlLgogIC0gSGludDogeW91IGNhbiB1c2UgdGhlIHBhbGFlb2Nvb3JkaW5hdGVzIG9mIHRoZSBQQkRCIGRhdGEgdG8gYXNzaWduIGEgZ3JvdXAgdG8gZWFjaCBvY2N1cnJlbmNlLCB1c2UgdGhpcyB0byBjb2xvdXIgdGhlIHBvaW50cyBpbiBgZ2VvbV9wb2ludGAuCiAgLSBIaW50OiB1c2UgYHNjYWxlX2NvbG91cl9kaXNjcmV0ZWAgdG8gY29sb3VyIHRoZSBwb2ludHMuIFNlZSB0aGUgY29kZSBvZiBgcGFsYWVvZ2VvZ19tYXBfbmljZXRpZXNgIChgZnVuY3Rpb25zL3BhbGFlb2dlb2dfbWFwX25pY2V0aWVzLlJgKSBmb3IgYW4gZXhhbXBsZSBvZiBkb2luZyB0aGlzLgoKCiMgU3VnZ2VzdGVkIHNvbHV0aW9ucyB0byBleGVyY2lzZXMgIwoKTm90IGFsbCBvZiB0aGUgZXhlcmNpc2UgcXVlc3Rpb25zIGhhdmUgYSBzaW5nbGUgb2J2aW91cyBzb2x1dGlvbiwgcGFydGljdWxhcmx5IG9uZXMgd2hlcmUgeW91IHBpY2sgeW91ciBmYXZvdXJpdGUgcGVyaW9kLiBCdXQgaGVyZSBhcmUgc29tZSBjb2RlIHN1Z2dlc3Rpb25zIGZvciB5b3UgdG8gY2hlY2sgYWdhaW5zdC4KCiMjIEV4ZXJjaXNlcyAxICMjCgoxLiBGaW5kIGFuIGV4YW1wbGUgb2YgYSBwYWxhZW9nZW9ncmFwaGljYWwgbWFwIGZvciB5b3VyIGZhdm91cml0ZSB0aW1lIHBlcmlvZC4KICAtIFlvdSBjYW4gaGF2ZSBhIGxvb2sgYXQgRGVlcCBUaW1lIE1hcHMgb3IgUGFsZW9tYXAgZm9yIGVhc3kgZXhhbXBsZXMsIG9yIHlvdSBjYW4gZmluZCBvdGhlcnMgaW4gcGFwZXJzLgoyLiBIYXZlIGEgbG9vayBpbiB0aGUgZm9sZGVyIGBHcGxhdGVzU2FtcGxlRGF0YWAgdG8gc2VlIHdoYXQgb3RoZXIgcHJvamVjdHMgYXJlIGluY2x1ZGVkLiAKICAtIFRoZSBgR3BsYXRlc1NhbXBsZURhdGEvRmVhdHVyZUNvbGxlY3Rpb25zYCBkaXJlY3RvcnkgaXMgdGhlIG9uZSB0byBsb29rIGF0LiBJdCBpbmNsdWRlczoKICAgICsgT3RoZXIgcGxhdGUgcmVjb25zdHJ1Y3Rpb25zLgogICAgKyBPY2VhbiBib3VuZGFyaWVzLgogICAgKyBQbGF0ZSBmbG93IGxpbmVzLgogICAgKyBMYXJnZSBpZ25lb3VzIHByb3ZpbmNlcyDigKYgYW1vbmcgb3RoZXIgdGhpbmdzLgoKIyMgRXhlcmNpc2VzIDIgIyMKCjEuIEhhdmUgYSBsb29rIGF0IHRoZSBbR1dTIGRvY3VtZW50YXRpb25dKDxodHRwczovL2dpdGh1Yi5jb20vR1BsYXRlcy9ncGxhdGVzX3dlYl9zZXJ2aWNlX2RvYy93aWtpPikuIFdoYXQgYWRkcmVzcyB3b3VsZCB5b3UgdXNlIHRvIGdldCByZWNvbnN0cnVjdGVkIGNvYXN0bGluZXMgaW4gdGhlIGVhcmx5IENhcmJvbmlmZXJvdXMgdXNpbmcgdGhlIEBNYXR0aGV3czIwMTZHUEMgbW9kZWw/CiAgLSBgImh0dHBzOi8vZ3dzLmdwbGF0ZXMub3JnL3JlY29uc3RydWN0L2NvYXN0bGluZXMvPyZ0aW1lPTM1MCZtb2RlbD1NQVRUSEVXUzIwMTZfbWFudGxlX3JlZiJgCiAgLSBZb3UgY291bGQgYWxzbyB1c2UgYCJNQVRUSEVXUzIwMTZfcG1hZ19yZWYiYC4gVGhlc2UgYXJlIHR3byBkaWZmZXJlbnQgcmVjb25zdHJ1Y3Rpb24gbWV0aG9kcy4KMi4gT3BlbiBhbiBleGFtcGxlIG9mIHRoZSBPR1ItR01UIGRhdGEgZnJvbSB0aGUgR1dTLCBlaXRoZXIgZnJvbSB0aGUgYGRhdGEvR1dTYCBmb2xkZXIgb3IgYnkgZG93bmxvYWRpbmcgaXQuIENhbiB5b3Ugc2VlIGhvdyB0aGUgcG9seWdvbnMgYXJlIHN0b3JlZD8gSG93IGFyZSBkaWZmZXJlbnQgcG9seWdvbnMgaWRlbnRpZmllZD8KICAtIFRoZSBtZXRhZGF0YSBhdCB0aGUgdG9wIGhhcyBsaW5lcyBiZWdpbm5pbmcgd2l0aCBgIyBAYCwgaW5jbHVkaW5nIGRlc2NyaWJpbmcgaG93IHRoZSBkYXRhIGZvciBlYWNoIHBvbHlnb24gaXMgb3JnYW5pc2VkLgogIC0gRWFjaCBwb2x5Z29uIGhhcyBhIGxpbmUgb2YgbWV0YWRhdGEgZGVzY3JpYmluZyBpdCBhbmQgYEBQYCBpbmRpY2F0aW5nIGl0J3MgYSBwb2x5Z29uLgogIC0gU29tZXRpbWVzIHdpdGhvdXQgbWV0YWRhdGEgZm9yIGVhY2ggcG9seWdvbiwgdGhleSBhcmUgaW5kaWNhdGVkIHdpdGggbnVtYmVyczogYEBQMWAsIGBAUDJgIGV0Yy4KMy4gTm93IGxvb2sgYXQgdGhlIHRpZGllZCB2ZXJzaW9uIGluIFIsIGkuZS4gYGtpbW1lcmlkZ2lhbl9jb2FzdGxpbmVzYCBvciBga2ltbWVyaWRnaWFuX3BvbHlnb25zYC4gQnkgZGVmYXVsdCB0aGlzIHdpbGwgb25seSBzaG93IHRoZSBmaXJzdCAxMCByb3dzLCBidXQgeW91IGNhbiBzZWUgbW9yZSB3aXRoLCBmb3IgZXhhbXBsZSwgYGhlYWQoa2ltbWVyaWRnaWFuX3BvbHlnb25zLCBuID0gNTBMKWAuIENhbiB5b3Ugc2VlIGhvdyB0aGUgT0dSLUdNVCBkYXRhIGlzIHRyYW5zZmVycmVkIHRvIHRoaXMgdGlkeSBmb3JtYXQ/CiAgLSBUaGUgZGF0YSBpcyBzdG9yZWQgaW4gYSB0aWJibGUgd2l0aCBlYWNoIHBvaW50IGluIGEgcm93IGFuZCBjb2x1bW5zIGZvciB0aGUgbG9uZ2l0dWRlIGFuZCBsYXRpdHVkZSBvZiB0aGUgcG9pbnRzLgogIC0gVGhlIG9yZGVyIHRoYXQgdGhlIHBvaW50cyBzaG91bGQgYmUgcGxvdCBhbmQgdGhlIHBpZWNlLCBncm91cCwgYW5kIGlkIG9mIHRoZSBwb2x5Z29uIHRoYXQgdGhleSBiZWxvbmcgdG8gYXJlIGFsc28gaW5jbHVkZWQgdG8gc2VwYXJhdGUgdGhlIHNoYXBlcy4KICAtIFRoZXNlIElEIGNvbHVtbnMgYXJlIHRha2VuIGZyb20gdGhlIG1ldGFkYXRhIGZvciBlYWNoIHBvbHlnb24gZGVmaW5lIGluIHRoZSBpbnB1dCBPR1ItR01UIGZpbGUuCjQuIFBsYXkgYXJvdW5kIHdpdGggdGhlIGlucHV0cyB0byB0aGUgcGxvdCBhYm92ZS4gSG93IG1lc3N5IG9yIGNvbG91cmZ1bCBjYW4geW91IG1ha2UgdGhpcyBtYXA/IFdoYXQgb3B0aW9ucyBhcmUgdGhlcmUgaW4gYHRoZW1lX21hcCgpYD8gKEhpbnQ6IHVzZSBgP3RoZW1lX21hcGAgdG8gc2VlLikKICAtIEknbGwgbGVhdmUgdGhpcyB0byB5b3VyIGltYWdpbmF0aW9uLgoKIyMgRXhlcmNpc2VzIDMgIyMKCjEuIFRyeSBwbG90dGluZyB0aGlzIG1hcCB3aXRoIGRpZmZlcmVudCBwcm9qZWN0aW9ucyAoc2VlIGFib3ZlIGFuZCBgP21hcHByb2plY3RgKS4gRG9lcyB0aGlzIHdvcmsgd2VsbCBmb3IgYWxsIHByb2plY3Rpb25zPyBXaHk/CiAgLSBTb21lIG9mIHRoZSBwcm9qZWN0aW9ucyBtb3ZlIHRoZSBsaW5lIG9mIDDCsCBsb25naXR1ZGUgYXdheSBmcm9tIHRoZSBjZW50cmUgb3IgaGF2ZSBwb2x5Z29ucyB0aGF0IGNyb3NzIGZyb20gb25lIHNpZGUgb2YgdGhlIG1hcCB0byB0aGUgb3RoZXIuIFRoaXMgY2FuIHNvbWV0aW1lcyBsZWFkIHRvIHNoYXBlcyBiZWluZyBkcmF3biByaWdodCBhY3Jvc3MgdGhlIG1hcC4gSSdtIG5vdCBzdXJlIHdoZXRoZXIgdGhlIGJlc3Qgd2F5IHRvIGNvdW50ZXJhY3QgdGhpcyBpcyBpbiByZWRyYXdpbmcgdGhlIHBvbHlnb25zIG9yIHNvbWV0aGluZyB0byBkbyB3aXRoIHRoZSBtYXAgcHJvamVjdGlvbi4KMi4gTG9vayBhdCB0aGUgY29kZSBiZWhpbmQgYHBhbGFlb2dlb2dfbWFwX25pY2V0aWVzKClgIChpbiBgZnVuY3Rpb25zL3BhbGFlb2dlb2dfbWFwX25pY2V0aWVzLlJgKS4gTW9kaWZ5IHRoaXMgdG8gYWRkIGRpZmZlcmVudCBsaW5lcyBvZiBsYXRpdHVkZS4gQ2FuIHlvdSBhZGQgbGluZXMgb2YgbG9uZ2l0dWRlIHRvbz8gV2hhdCBhYm91dCBjaGFuZ2luZyB0aGUgY29sb3VyPwogIC0gSW4gYHBhbGFlb2dlb2dfbWFwX25pY2V0aWVzYCBJIHN0b3JlZCB0aGUgbGluZXMgb2YgbGF0aXR1ZGUgdGhhdCBJIHdhbnQgYXMgYSB0aWJibGUgdGhhdCBkZXNjcmliZSBfbGluZSBzZWdtZW50cy5fIE5ldyBsaW5lcyBvZiBsYXRpdHVkZSBjYW4gYmUgYWRkZWQgYnkgY3JlYXRpbmcgYSBuZXcgcm93IHdpdGggdGhlIHZhbHVlIF95XyBzZXQgdG8geW91ciBsYXRpdHVkZS4gVGhlIGxpbmVzIGFyZSBkZXNjcmliZWQgYXMgZ29pbmcgZnJvbSAtMTgwwrDigJMrMTgwwrAgbG9uZ2l0dWRlIGF0IGEgc3BlY2lmaWMgc2luZ2xlIGxhdGl0dWRlLgogIC0gRm9yIGxpbmVzIG9mIGxvbmdpdHVkZSwgSSdkIHN1Z2dlc3QgdXNpbmcgYSBuZXcgYGdlb21fc2VnbWVudGAgbGF5ZXIuIE1vZGlmeSB0aGUgY29kZSBzbyB0aGF0IHRoZSBfeV8gdmFsdWUgY292ZXJzIHRoZSByYW5nZSBvZiBsYXRpdHVkZXMg4oCTOTDCsOKAkys5MMKwIGF0IGEgc3BlY2lmaWMgbG9uZ2l0dWRlLiBIZXJlJ3MgYW4gZXhhbXBsZSBkcmF3aW5nIGxpbmVzIG9mIGxvbmdpdHVkZSBhdCAtNTDCsCwgMMKwIGFuZCA3MsKwOgoKYGBge3IgZXhlcmNpc2UzLjIsIGV2YWwgPSBGQUxTRX0KZ2VvbV9zZWdtZW50KAogIGRhdGEgPSB0aWJibGUoCiAgICB4ID0gYygtNTAsIDAsIDcyKSwKICAgIHkgPSByZXAoLTkwLCAzKSwKICAgIHllbmQgPSByZXAoOTAsIDMpCiAgKSwKICBhZXMoeCA9IHgsIHhlbmQgPSB4LCB5ID0geSwgeWVuZCA9IHllbmQpLAogIGNvbG91ciA9ICJncmV5NzAiLCBzaXplID0gMC4zCikKYGBgCgozLiBDYW4geW91IHRyeSBjcmVhdGluZyB5b3VyIG93biBwYWxhZW9nZW9ncmFwaGljYWwgbWFwIGZvciB5b3VyIGZhdm91cml0ZSB0aW1lPyBUaGlzIHNob3VsZCBiZSBkb25lIG9uIHlvdXIgb3duIGNvbXB1dGVyLiBGb2xsb3cgdGhlIGluc3RydWN0aW9ucyBhYm92ZSB0byBleHBvcnQgZGF0YSBmcm9tIEdQbGF0ZXMgdGhlbiBwbG90IGluIFIsIG1ha2luZyBzdXJlIHlvdSBjaGFuZ2UgYWxsIHRoZSBmaWxlIGFuZCBvYmplY3QgbmFtZXMuCiAgLSBoZXJlIHlvdSdsbCBoYXZlIHRvIG1vZGlmeSB0aGUgY29kZSBhYm92ZSBmb3IgeW91ciBvd24gR1BsYXRlcyBkYXRhLiBSZW1lbWJlciB0byBhZGQgaW4gdGhlIGljZSBjYXBzIHRvIHRoZSBsYXllciBpZiB5b3UgcGljayBhIHRpbWUgd2l0aCB0aGVzZSwgc3VjaCBhcyB0aGUgQ2FyYm9uaWZlcm91cyBvciB0aGUgTmVvZ2VuZS4KCiMjIEV4ZXJjaXNlcyA0ICMjCgoxLiBMb29rIGF0IHRoZSBQQkRCIHdlYiBBUEkgKDxodHRwczovL3BhbGVvYmlvZGIub3JnL2RhdGExLjI+KS4gV2hhdCBvdGhlciBvcHRpb25zIGFuZCBkYXRhIHNldHMgY2FuIHlvdSBhY2Nlc3Mgd2l0aCB0aGlzPyBDYW4geW91IGNyYWZ0IGEgVVJMIHRoYXQgd2lsbCBkb3dubG9hZCBvY2N1cnJlbmNlIGRhdGEgb2YgVGl0aG9uaWFuIGJpdmFsdmVzLgogIC0gImh0dHBzOi8vcGFsZW9iaW9kYi5vcmcvZGF0YTEuMi9vY2NzL2xpc3QuY3N2P2Jhc2VfbmFtZT1CaXZhbHZpYSZpbnRlcnZhbD1UaXRob25pYW4mc2hvdz1wYWxlb2xvYyIgCjIuIFRyeSBhZGRpbmcgY29sb3VyIG9yIHNoYXBlcyB0byB5b3VyIG9jY3VycmVuY2UgcG9pbnRzIHVzaW5nIHRoZSBvcHRpb25zIGluIGBnZW9tX3BvaW50YC4KICAtIFVzZSB0aGUgYGNvbG91cmAgYW5kIGBzaGFwZWAgYXJndW1lbnRzLgozLiBEb3dubG9hZCBhbmQgcGxvdCB0aGUgcGFsYWVvZ2VvZ3JhcGhpY2FsIG1hcCBhbmQgb2NjdXJyZW5jZXMgZm9yIHlvdXIgZmF2b3VyaXRlIGdyb3VwIGluIHlvdXIgZmF2b3VyaXRlIHN0YWdlLiBBZ2FpbiB0aGlzIHNob3VsZCBiZSBkb25lIG9uIHlvdXIgb3duIGNvbXB1dGVyLiBCZXdhcmUgaXQgbWF5IHRha2UgYSB3aGlsZSBpZiB5b3Ugd2FudCB0byBwbG90IG1hbnkgb2NjdXJyZW5jZXMuCiAgLSBVc2UgdGhlIGNvZGUgYWJvdmUsIGJ1dCBjaGFuZ2UgdGhlIHJlbGV2YW50IFVSTHMgYW5kIGRhdGEgZmlsZXMgdG8geW91ciBvd24gR1BsYXRlcyBhbmQgUEJEQiBkYXRhLiBEb24ndCBmb3JnZXQgdG8gYWRkIGljZSBjYXBzIGlmIHlvdSBoYXZlIHRoZW0uCiAgLSBIb3BlZnVsbHkgdGhlIFBCREIgQVBJIHdpbGwgYmUgd29ya2luZyBhcyBpdCB3YXNuJ3Qgd2hlbiBJIHdhcyB3cml0aW5nIHRoaXMhCjQuIEl0J3MgYWxzbyB1c2VmdWwgdG8gc2VwYXJhdGUgb3V0IG9jY3VycmVuY2VzIG9uIHRoZSBtYXAsIGZvciBpbnN0YW5jZSwgY2FuIHlvdSBjb2xvdXIgb2NjdXJyZW5jZXMgd2l0aGluIHRoZSBvdXRzaWRlIHRoZSB0cm9waWNzIGRpZmZlcmVudGx5PyBzYXkgcmVkIGluIHRoZSB0cm9waWNzICjCsTIzLjXCsCkgYW5kIGJsdWUgb3V0c2lkZS4KICAtIFlvdSdsbCBuZWVkIHRvIGFzc2lnbiBhIGNvbHVtbiBvZiBpZGVudGlmaWVycyBmb3IgdHJvcGljYWwgYW5kIG5vbi10cm9waWNhbCBvY2N1cnJlbmNlcy4gQmVsb3cgaXMgYW4gZXhhbXBsZSB1c2luZyB0aGUgX2RwbHlyXyBmdW5jdGlvbiBgY2FzZV93aGVuYC4KICAtIFdpdGggdGhhdCBkb25lIGl0J2xsIGZpdCByaWdodCBpbnRvIHRoZSBwbG90dGluZyBjb2RlIGZyb20gZWFybGllciwgYnV0IHlvdSB3aWxsIG5lZWQgdG8gc3BlY2lmeSB0aGUgYGNvbG91cmAgYXJndW1lbnQuIElmIHlvdSB3YW50IHRvIG1ha2UgaXQgYmx1ZSBhbmQgcmVkIHRoZW4geW91IGNhbiBhZGQgYSBzY2FsZS4KCmBgYHtyIGV4ZXJjaXNlNC40LCBmaWcud2lkdGggPSA3LCBmaWcuaGVpZ2h0ID0gNCwgZmlnLmNhcCA9ICIqKk9jY3VycmVuY2VzIG9mIGljaHRoeW9zYXVycyBpbiB0aGUgQ2FsbG92aWFu4oCTVGl0aG9uaWFuIGluZGljYXRlZCBieSBsYXRpdHVkZSByZWdpb24uKiogUGFsYWVvZ2VvZ3JhcGhpY2FsIG1hcHMgc2hvd3MgZGlzdHJpYnV0aW9uIG9mIGxhbmQgaW4gdGhlIEtpbW1lcmlkZ2lhbiAoMTU1IE1hKSByZWNvbnN0cnVjdGVkIGJ5IEBDYW8yMDE3QmIuIn0KZXhfb2NjX2ljaHRoeW9zYXVycyA8LQogIG9jY19pY2h0aHlvc2F1cnMgJT4lCiAgICBtdXRhdGUoCiAgICAgIHRyb3BpY2FsID0gY2FzZV93aGVuKAogICAgICAgIHBhbGVvbGF0IDw9IDIzLjUgJiBwYWxlb2xhdCA+PSAtMjMuNSB+ICJ0cm9waWNhbCIsCiAgICAgICAgcGFsZW9sYXQgPiAyMy41IHwgcGFsZW9sYXQgPCAtMjMuNSAgIH4gIm5vbi10cm9waWNhbCIKICAgICAgKSAlPiUKICAgICAgICBhc19mYWN0b3IoKQogICAgKQoKZXhfb2NjX3Bsb3QgPC0KICBtYXBfcGxvdCArCiAgICBnZW9tX3BvaW50KAogICAgICBkYXRhID0gZXhfb2NjX2ljaHRoeW9zYXVycywKICAgICAgYWVzKAogICAgICAgIHggPSBwYWxlb2xuZywKICAgICAgICB5ID0gcGFsZW9sYXQsCiAgICAgICAgY29sb3VyID0gdHJvcGljYWwKICAgICAgKSwKICAgICAgbmEucm0gPSBUUlVFCiAgICApICsKICAgIHNjYWxlX2Rpc2NyZXRlX21hbnVhbCgKICAgICAgdmFsdWVzID0gCiAgICAgICAgYygKICAgICAgICAgICJ0cm9waWNhbCIgPSAicmVkIiwKICAgICAgICAgICJub24tdHJvcGljYWwiID0gImJsdWUiCiAgICAgICAgKSwKICAgICAgICBhZXN0aGV0aWNzID0gYygiY29sb3VyIiksCiAgICAgICAgbmFtZSA9ICJMYXRpdHVkZSIKICAgICAgKQpleF9vY2NfcGxvdApgYGAKCgojIFJlZmVyZW5jZXMgIwoK